1
0
mirror of https://github.com/webslides/WebSlides.git synced 2025-08-17 02:24:12 +02:00

Merge pull request #41 from Belelros/master

WebSlides 1.0 - Architecture change
This commit is contained in:
José Luis Antúnez
2017-02-23 12:53:46 +01:00
committed by GitHub
34 changed files with 1898 additions and 879 deletions

20
.editorconfig Normal file
View File

@@ -0,0 +1,20 @@
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 233
[*.json]
indent_style = space
indent_size = 2
[*.yml]
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false

18
.gitignore vendored Normal file
View File

@@ -0,0 +1,18 @@
# IDE files #
#############
.idea/
# Third Party #
###############
node_modules/
# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
static/js/webslides*

View File

@@ -1,13 +1,50 @@
## 0.2 (2017-02-22) <<<<<<< HEAD
# 1.0.0 (2017-02-23)
- Auto slide (Demo: why-webslides.html) This release is a special one since it sets up in the path of a better development environment. Although it's far from
perfect, it's a solid beginning.
## 0.1.1 (2017-02-11) All the code has been migrated from jQuery with ES5 to vanilla JavaScript with ES2015 (or ES6) and is fully modular.
This means that WebSlides is a (base module)[src/js/modules/webslides.js] with a solid API (few public methods) and
it's extended by (plugins)[src/js/plugins]. This leads to more granularity and less code to dive through while fixing a
bug.
The benefit from this approach is that now it's really easy to extend WebSlides to achieve what you need. You can also
overwrite current plugins. Say you don't like the current navigation with arrows and want to create a menu instead, you
can just write that for yourself with your custom needs and register it as `nav` and it will overwrite our nav with
your code.
We hope this leads to a better environment in which WebSlides can grow better.
All the technical specs live now in [this document](docs/technical.md).
## Bugfixes
- Fixed a bug with back/next buttons on the browser which lead the nav bar to not work.
## New Features
- Linking to slides without window open.
- Added custom events to listen for. `ws:init` whenever webslides is ready and `ws:slide-change` whenever a slide changes.
- Added play/stop methods.
## Breaking Changes
- This "stable" release drops the jQuery requirement and leans on ES2015 for the architecture. Hence, it's no longer possible
to use the library as before.
# 0.2.0 (2017-02-22)
## New Features
- Adding autoslide option.
# 0.1.1 (2017-02-11)
- Transform the library into an object. - Transform the library into an object.
- .tabs removed. - `.tabs` removed.
- webslides-lite.js removed. - `webslides-lite.js` removed.
## 0.1 (2017-01-08) # 0.1.0 (2017-01-08)
- Initial release. - Initial release.

View File

@@ -1,7 +1,11 @@
# WebSlides = Good Karma # WebSlides = Good Karma
Finally, everything you need to make HTML presentations in a beautiful way. Just the essentials. You can create your own presentation instantly. Simply choose a demo and customize it in minutes — [https://webslides.tv/demos](https://webslides.tv/demos).
A new release (at least) every 8th day of the month. Version 0.1: Jan 8, 2017. [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](http://opensource.org/licenses/MIT)
[![Twitter](https://img.shields.io/twitter/url/https/github.com/jlantunez/webslides.svg?style=social)](https://twitter.com/webslides)
Finally, everything you need to make HTML presentations in a beautiful way. Just the essentials. You can create your own presentation instantly. Simply choose a demo and customize it in minutes — https://webslides.tv/demos.
A new release (at least) every 8th day of the month.
### Why WebSlides? ### Why WebSlides?
Good karma and productivity. Just a basic knowledge of HTML and CSS is required. Designers, marketers, and journalists can now focus on the content. Good karma and productivity. Just a basic knowledge of HTML and CSS is required. Designers, marketers, and journalists can now focus on the content.
@@ -18,54 +22,34 @@ Good karma and productivity. Just a basic knowledge of HTML and CSS is required.
- Fonts: Roboto, Maitree (Serif), and San Francisco. - Fonts: Roboto, Maitree (Serif), and San Francisco.
- Vertical rhythm (use multiples of 8). - Vertical rhythm (use multiples of 8).
### Markup ## Markup
- Code is clean and scalable. It uses intuitive markup with popular naming conventions. There's no need to overuse classes or nesting. - Code is clean and scalable. It uses intuitive markup with popular naming conventions. There's no need to overuse classes or nesting.
- Each parent <code>&lt;section&gt;</code> in the #webslides element is an individual slide. - Each parent `<section>` in the `#webslides` element is an individual slide.
<pre>&lt;article id="webslides"&gt; ```html
&lt;section&gt; <article id="webslides">
&lt;h1&gt;Slide 1&lt;/h1&gt; <section>
&lt;/section&gt; <h1>Slide 1</h1>
&lt;section class="bg-black aligncenter"&gt; </section>
<span class="code-comment">&lt;!-- .wrap = container 1200px --&gt;</span> <section class="bg-black aligncenter">
&lt;div class="wrap"&gt; <!-- .wrap = container 1200px -->
&lt;h1&gt;Slide 2&lt;/h1&gt; <div class="wrap">
&lt;/div&gt; <h1>Slide 2</h1>
&lt;/section&gt; </div>
&lt;/article&gt;</pre> </section>
</article>
#### Vertical Sliding
<pre>&lt;article id="webslides" class="vertical"&gt;</pre>
### How it works
You need to add the follow javascript to initialize the webslides object.
```javascript
var slide = jQuery('#webslides').webslides();
``` ```
#### Auto slide ### Vertical Sliding
```javascript ```html
var slide = jQuery('#webslides').webslides({interval: 5000}); <article id="webslides" class="vertical">
```
Now you can use the slide with these functions:
```javascript
// Moving to next slide
slide.nextSlide();
// Moving to previous slide
slide.previousSlide();
// Moving to a specific slide
slide.goToSlide(n);
``` ```
### What's in the download? ### What's in the download?
The download includes demos and images (devices and logos). The download includes demos and images (devices and logos).
All content is for demo purposes only. Images are property of their respective owners. All content is for demo purposes only. Images are property of their respective owners.
``` ```
@@ -84,16 +68,17 @@ webslides/
### CSS Syntax (classes) ### CSS Syntax (classes)
- Typography: .text-landing, .text-data, .text-intro... - Typography: `.text-landing`, `.text-data`, `.text-intro`...
- Background Colors: .bg-primary, .bg-apple, .bg-blue... - Background Colors: `.bg-primary`, `.bg-apple`, `.bg-blue`...
- Background Images: .background,.background-center-bottom... - Background Images: `.background`,`.background-center-bottom`...
- Cards: .card-50, .card-40... - Cards: `.card-50`, `.card-40`...
- Flexible Blocks: .flexblock.clients, .flexblock.metrics... - Flexible Blocks: `.flexblock.clients`, `.flexblock.metrics`...
### Extensions ### Extensions
You can add: You can add:
- [Unsplash](https://unsplash.com) photos - [Unsplash](https://unsplash.com) photos
- [animate.css](https://daneden.github.io/animate.css) - [animate.css](https://daneden.github.io/animate.css)
- [particles.js](https://github.com/VincentGarreau/particles.js) - [particles.js](https://github.com/VincentGarreau/particles.js)
@@ -101,9 +86,16 @@ You can add:
### License ### License
WebSlides is licensed under the [MIT License](https://opensource.org/licenses/MIT). WebSlides is licensed under the [MIT License](https://opensource.org/licenses/MIT).
Use it to make something cool. Use it to make something cool.
### Dive In!
Please check out:
- Want to get techie? Read [our technical docs](docs/technical.md)
- Do not miss [our demos](https://webslides.tv/)
### Credits ### Credits
- WebSlides was created by [@jlantunez](https://twitter.com/jlantunez) using [Cactus](https://github.com/eudicots/Cactus). - WebSlides was created by [@jlantunez](https://twitter.com/jlantunez) using [Cactus](https://github.com/eudicots/Cactus).

View File

@@ -1933,16 +1933,13 @@
</main> </main>
<!--main--> <!--main-->
<!-- jQuery (required for slides to work) --> <script src="../static/js/svg-icons.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="../static/js/webslides.js"></script> <script src="../static/js/webslides.js"></script>
<script>
<script type="text/javascript"> window.ws = new WebSlides();
var slide = jQuery('#webslides').webslides();
</script> </script>
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) --> <!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
<script defer src="../static/js/svg-icons.js"></script> <script defer src="../static/js/svg-icons.js"></script>
</body> </body>
</html> </html>

View File

@@ -319,7 +319,11 @@
<section> <section>
<div class="wrap"> <div class="wrap">
<h1>Navigation</h1> <h1>Navigation</h1>
<ul class="tabs">
<li class="tab current" data-tab="tab-1">ul.tabs</li>
<li class="tab" data-tab="tab-2">columns</li>
</ul>
<div id="tab-1" class="tab-content current">
<nav role="navigation"> <nav role="navigation">
<ul> <ul>
<li><a href="">About</a></li> <li><a href="">About</a></li>
@@ -368,8 +372,9 @@
</ul> </ul>
</nav> </nav>
<p>nav.navbar</p> <p>nav.navbar</p>
</div>
<hr> <!-- end .tab-content -->
<div id="tab-2" class="tab-content">
<div class="grid"> <div class="grid">
<div class="column"> <div class="column">
<h3>Company</h3> <h3>Company</h3>
@@ -430,6 +435,8 @@
<!-- .end .column --> <!-- .end .column -->
</div> </div>
<!-- .end .grid --> <!-- .end .grid -->
</div>
<!-- end .tab-content -->
</div> </div>
<!-- .end .wrap --> <!-- .end .wrap -->
</section> </section>
@@ -1796,8 +1803,49 @@
<section class="aligncenter"> <section class="aligncenter">
<!--.wrap = container 1200px --> <!--.wrap = container 1200px -->
<div class="wrap"> <div class="wrap">
<h1 class="text-landing">Tell a Story</h1> <div id="tab-3" class="tab-content current">
<p class="text-intro"><strong>Hi, this is WebSlides</strong>. HTML presentations made simple. <br>I'm a cute solution with clean markup and <strong>lovely CSS</strong>.</p> <h1 class="text-landing">Tell a Story</h1>
<p class="text-intro"><strong>Hi, this is WebSlides</strong>. HTML presentations made simple. <br>I'm a cute solution with clean markup and <strong>lovely CSS</strong>.</p>
</div>
<div id="tab-4" class="tab-content">
<ul class="flexblock features">
<li>
<div>
<svg class="fa-heart-o">
<use xlink:href="#fa-heart-o"></use>
</svg>
<h2>Indexed content</h2>
Sharing is caring.
</div>
</li>
<li>
<div>
<h2>
<svg class="fa-magic">
<use xlink:href="#fa-magic"></use>
</svg>
Just essential features
</h2>
Keyboard navigation...
</div>
</li>
<li>
<div>
<svg class="fa-bolt">
<use xlink:href="#fa-bolt"></use>
</svg>
<h2>
Prototype faster
</h2>
with clean code
</div>
</li>
</ul>
</div>
<ul class="tabs">
<li class="tab current" data-tab="tab-3">Purpose</li>
<li class="tab" data-tab="tab-4">Benefits</li>
</ul>
</div> </div>
</section> </section>
<section class="bg-black aligncenter"> <section class="bg-black aligncenter">
@@ -3078,16 +3126,14 @@
</main> </main>
<!--main--> <!--main-->
<!-- jQuery (required for slides to work) --> <script src="../static/js/svg-icons.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="../static/js/webslides.js"></script> <script src="../static/js/webslides.js"></script>
<script>
<script type="text/javascript"> window.ws = new WebSlides();
var slide = jQuery('#webslides').webslides();
</script> </script>
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) --> <!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
<script defer src="../static/js/svg-icons.js"></script> <script defer src="../static/js/svg-icons.js"></script>
</body> </body>
</html> </html>

View File

@@ -92,7 +92,7 @@
</header> </header>
<main role="main"> <main role="main">
<article id="webslides" class="vertical"> <article> <!-- Slideshow? id="webslides" -->
<!-- Quick Guide <!-- Quick Guide
- Each parent <section> in the <article id="webslides"> element is an individual slide. - Each parent <section> in the <article id="webslides"> element is an individual slide.
@@ -107,7 +107,7 @@
<h1><strong>WebSlides Demos</strong></h1> <h1><strong>WebSlides Demos</strong></h1>
<p class="text-intro">All of these presentations are free and responsive.<br> <p class="text-intro">All of these presentations are free and responsive.<br>
40+ <a href="../demos/components.html" title="WebSlides Components">components</a> with a solid <a href="../demos/classes.html" title="WebSlides Classes">CSS architecture</a>.</p> 40+ <a href="../demos/components.html" title="WebSlides Components">components</a> with a solid <a href="../demos/classes.html" title="WebSlides Classes">CSS architecture</a>.</p>
<p>Share your slides using <a target="_blank" href="https://twitter.com/search?f=tweets&q=%23webslides&src=typd" title="#WebSlides on Twitter">#WebSlides</a>.</p> <p>Share your slides using <a href="https://twitter.com/search?q=%23webslides&amp;src=typd" title="#WebSlides on Twitter">#WebSlides</a>.</p>
</div> </div>
<!-- .end .wrap --> <!-- .end .wrap -->
</section> </section>
@@ -222,16 +222,14 @@
</main> </main>
<!-- end main --> <!-- end main -->
<!-- jQuery (required for slides to work) --> <script src="../static/js/svg-icons.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="../static/js/webslides.js"></script> <script src="../static/js/webslides.js"></script>
<script>
<script type="text/javascript"> window.ws = new WebSlides();
var slide = jQuery('#webslides').webslides();
</script> </script>
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) --> <!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
<script defer src="../static/js/svg-icons.js"></script> <script defer src="../static/js/svg-icons.js"></script>
</body> </body>
</html> </html>

View File

@@ -843,16 +843,14 @@
</main> </main>
<!--main--> <!--main-->
<!-- jQuery (required for slides to work) --> <script src="../static/js/svg-icons.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="../static/js/webslides.js"></script> <script src="../static/js/webslides.js"></script>
<script>
<script type="text/javascript"> window.ws = new WebSlides();
var slide = jQuery('#webslides').webslides();
</script> </script>
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) --> <!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
<script defer src="../static/js/svg-icons.js"></script> <script defer src="../static/js/svg-icons.js"></script>
</body> </body>
</html> </html>

View File

@@ -1918,16 +1918,13 @@
</main> </main>
<!--main--> <!--main-->
<!-- jQuery (required for slides to work) --> <script src="../static/js/svg-icons.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="../static/js/webslides.js"></script> <script src="../static/js/webslides.js"></script>
<script>
<script type="text/javascript"> window.ws = new WebSlides();
var slide = jQuery('#webslides').webslides();
</script> </script>
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) --> <!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
<script defer src="../static/js/svg-icons.js"></script> <script defer src="../static/js/svg-icons.js"></script>
</body> </body>
</html> </html>

View File

@@ -1858,16 +1858,14 @@
</main> </main>
<!--main--> <!--main-->
<!-- jQuery (required for slides to work) --> <script src="../static/js/svg-icons.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="../static/js/webslides.js"></script> <script src="../static/js/webslides.js"></script>
<script>
<script type="text/javascript"> window.ws = new WebSlides();
var slide = jQuery('#webslides').webslides();
</script> </script>
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) --> <!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
<script defer src="../static/js/svg-icons.js"></script> <script defer src="../static/js/svg-icons.js"></script>
</body> </body>
</html> </html>

View File

@@ -66,7 +66,6 @@
<!-- Android --> <!-- Android -->
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#333333"> <meta name="theme-color" content="#333333">
</head> </head>
<body> <body>
<header role="banner"> <header role="banner">
@@ -339,13 +338,11 @@
</main> </main>
<!--main--> <!--main-->
<!-- jQuery (required for slides to work) --> <script src="../static/js/svg-icons.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="../static/js/webslides.js"></script> <script src="../static/js/webslides.js"></script>
<!-- Autoslide 5 seconds. If you don't want autoslide, remove: {autoslide: 5000} -->
<!-- Autoslide 5 seconds. If you don't want autoslide, remove: {interval: 5000} --> <script>
<script type="text/javascript"> window.ws = new WebSlides({ autoslide: 5000 });
var slide = jQuery('#webslides').webslides({interval: 5000});
</script> </script>
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) --> <!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->

135
docs/technical.md Normal file
View File

@@ -0,0 +1,135 @@
## Project Setup
This project assumes you have NodeJS. You should also have npm installed as well (this usually comes packaged with Node). Once you have it cloned, you should run `npm install` to get all the dependencies.
Finally, run one of the following commands in the cloned directory:
- `npm run dev`: This starts a dev server with autoreload on the port `8080`.
- `npm run build`: This creates the `dist` files.
## JavaScript
In order to bootstrap the WebSlides you'll need to create a instance of it:
```javascript
const ws = new WebSlides();
```
That'll make everything run without any hassle.
### Options
WebSlides constructor accepts an object with options.
| Param | Type | Default | Description |
|-----------|----------------|-----------|-------------------------------------------------------------------------------|
| `autoslide` | `number` or `boolean` | `false` | Amount of milliseconds to wait to go to next slide automatically. |
```javascript
const ws = new WebSlides({
autoslide: false
});
```
### API
Do you want to get your hands dirty? This is the API for the WebSlides module:
<dl>
<dt><a href="#goToSlide">goToSlide(slideIndex, opt_forward)</a></dt>
<dd><p>Goes to a given slide.</p></dd>
<dt><a href="#goNext">goNext()</a></dt>
<dd><p>Goes to the next slide.</p></dd>
<dt><a href="#goPrev">goPrev()</a></dt>
<dd><p>Goes to the previous slide.</p>
<dt><a href="#play">play()</a></dt>
<dd><p>Starts autosliding.</p>
<dt><a href="#stop">stop()</a></dt>
<dd><p>Stops autosliding.</p>
</dd>
<dt><a href="#registerPlugin">registerPlugin(key, cto)</a></dt>
<dd><p>Registers a plugin to be loaded when the instance is created. It allows
(on purpose) to replace default plugins.
Those being:</p>
<ul>
<li>Navigation</li>
<li>Hash</li>
<li>Keyboard</li>
</ul>
</dd>
</dl>
<a name="goToSlide"></a>
### `goToSlide(slideI, forward)`
Goes to a given slide.
| Param | Type | Description |
| --- | --- | --- | --- |
| slideIndex | <code>number</code> | The slide index. |
| forward | <code>boolean</code> | Whether we're forcing moving forward/backwards. This parameter is used only from the `goNext`, `goPrev` functions to adjust the scroll animations. |
<a name="goNext"></a>
### `goNext()`
Goes to the next slide. If the page is vertical, it will animate the scroll down.
<a name="goPrev"></a>
### `goPrev()`
Goes to the previous slide. If the page is vertical, it will animate the scroll up
<a name="play"></a>
### `play(time)`
Autoplays slides. If time is omitted, it will use the default time passed to the constructor. This is useful if you don't want to autoslide from the beginning but you want to add a button to do it.
| Param | Type | Description |
| --- | --- | --- | --- |
| time | <code>number</code> | Amount of milliseconds to wait to go to next slide automatically. |
<a name="stop"></a>
### `stop()`
Stops autosliding.
<a name="registerPlugin"></a>
### `registerPlugin(key, cto)`
Registers a plugin to be loaded when the instance is created. It allows
(on purpose) to replace default plugins.
Those being:
- Navigation
- Hash
- Keyboard
| Param | Type | Description |
| --- | --- | --- |
| key | <code>string</code> | They key under which it'll be stored inside of the instance, inside the plugins dict. |
| cto | <code>function</code> | Plugin constructor. |
### Plugin development
Almost every single feature of WebSlides is a plugin that can be overwritten and you are able to create your custom plugins. Just call `registerPlugin` (as seen above) **before creating** the instance:
```javascript
// Adding the constructor to WebSlides
WebSlides.registerPlugin('myPlugin', MyPlugin);
// Starting WebSlides
// Your plugin will be constructed at this time and it will receive the webslides instance as the only parameter.
const ws = new WebSlides();
// You can also access ws.plugins.myPlugin now
```
This allows you to rewrite the navigation to use a menu (for example) or add that missing piece of functionality you'd like to see. See [this part of the code](../src/js/modules/webslides.js#L11) to see all the plugins we're using and the name they're using.
Make sure to let us know so it could get added to the repo!
### Roadmap
* Fix crossbrowser issues. Safari mostly.
* Write tests

View File

@@ -94,7 +94,6 @@
<main role="main"> <main role="main">
<article id="webslides" class="vertical"> <article id="webslides" class="vertical">
<!-- Quick Guide <!-- Quick Guide
- Each parent <section> in the <article id="webslides"> element is an individual slide. - Each parent <section> in the <article id="webslides"> element is an individual slide.
- Vertical sliding = <article id="webslides" class="vertical"> - Vertical sliding = <article id="webslides" class="vertical">
@@ -384,17 +383,14 @@
</div> </div>
</footer> --> </footer> -->
<!-- jQuery (required for slides to work) --> <script src="static/js/svg-icons.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="static/js/webslides.js"></script> <script src="static/js/webslides.js"></script>
<script>
window.ws = new WebSlides();
<script type="text/javascript">
var slide = jQuery('#webslides').webslides();
</script> </script>
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) --> <!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
<script defer src="static/js/svg-icons.js"></script> <script defer src="static/js/svg-icons.js"></script>
</body> </body>
</html> </html>

48
package.json Normal file
View File

@@ -0,0 +1,48 @@
{
"name": "webslides",
"version": "1.0.0",
"description": "Making HTML presentations easy",
"main": "index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/jlantunez/webslides.git"
},
"keywords": [
"webslides",
"presentation",
"css"
],
"author": "Jose Luís Antúnez",
"license": "MIT",
"bugs": {
"url": "https://github.com/jlantunez/webslides/issues"
},
"homepage": "https://github.com/jlantunez/webslides#readme",
"devDependencies": {
"babel-cli": "^6.23.0",
"babel-core": "^6.23.1",
"babel-loader": "^6.3.2",
"babel-preset-es2015": "^6.22.0",
"npm-run-all": "^4.0.2",
"rimraf": "^2.6.0",
"webpack": "^2.2.1",
"webpack-dev-server": "^2.4.1"
},
"scripts": {
"prebuild": "rimraf static/js/webslide*",
"build": "npm-run-all --parallel build:*",
"build:main": "webpack",
"build:main.min": "webpack --output-filename [name].min.js -p",
"dev": "webpack-dev-server"
},
"babel": {
"presets": [
[
"es2015",
{
"modules": false
}
]
]
}
}

3
src/js/full.js Normal file
View File

@@ -0,0 +1,3 @@
import WebSlides from './modules/webslides';
window.WebSlides = WebSlides;

82
src/js/modules/slide.js Normal file
View File

@@ -0,0 +1,82 @@
import DOM from '../utils/dom';
const CLASSES = {
SLIDE: 'slide',
CURRENT: 'current'
};
/**
* Wrapper for the Slide section.
*/
export default class Slide {
/**
* Bootstraps the slide by saving some data, adding a class and hiding it.
* @param {Element} el Section element.
* @param {number} i Zero based index of the slide.
*/
constructor(el, i) {
/**
* @type {Element}
*/
this.el = el;
/**
* The section's parent.
* @type {Node}
*/
this.parent = el.parentNode;
/**
* @type {number}
*/
this.i = i;
this.el.id = 'section-' + (i + 1);
this.el.classList.add(CLASSES.SLIDE);
// Hide slides by default
this.hide();
}
/**
* Hides the node and removes the class that makes it "active".
*/
hide() {
DOM.hide(this.el);
this.el.classList.remove(CLASSES.CURRENT);
}
/**
* Shows the node and adds the class that makes it "active".
*/
show() {
DOM.show(this.el);
this.el.classList.add(CLASSES.CURRENT);
}
/**
* Moves the section to the bottom of the section's list.
*/
moveAfterLast() {
const last = this.parent.childNodes[this.parent.childElementCount - 1];
this.parent.insertBefore(this.el, last.nextSibling);
}
/**
* Moves the section to the top of the section's list.
*/
moveBeforeFirst() {
const first = this.parent.childNodes[0];
this.parent.insertBefore(this.el, first);
}
/**
* Checks whether an element is a valid candidate to be a slide by ensuring
* it's a "section" element.
* @param {Element} el Element to be checked.
* @return {boolean} Whether is candidate or not.
*/
static isCandidate(el) {
return el.nodeType === 1 && el.tagName === 'SECTION';
}
}

364
src/js/modules/webslides.js Normal file
View File

@@ -0,0 +1,364 @@
import Plugins from '../plugins/plugins';
import Slide from './slide';
import DOM from '../utils/dom';
import ScrollHelper from '../utils/scroll-to';
const CLASSES = {
VERTICAL: 'vertical'
};
// Default plugins
const PLUGINS = {
'grid': Plugins.Grid,
'hash': Plugins.Hash,
'keyboard': Plugins.Keyboard,
'nav': Plugins.Navigation,
'scroll': Plugins.Scroll,
'touch': Plugins.touch
};
export default class WebSlides {
/**
* Options for WebSlides
* @param {number|boolean} autoslide Is false by default. If a number is
* provided, it will autoslide every given milliseconds.
*/
constructor({
autoslide = false
} = {}) {
/**
* WebSlide element.
* @type {Element}
*/
this.el = document.getElementById('webslides');
/**
* Moving flag.
* @type {boolean}
*/
this.isMoving = false;
/**
* Slide's array.
* @type {?Array<Slide>}
*/
this.slides = null;
/**
* Current slide's index.
* @type {number}
* @private
*/
this.currentSlideI_ = -1;
/**
* Current slide reference.
* @type {?Slide}
* @private
*/
this.currentSlide_ = null;
/**
* Max slide index.
* @type {number}
* @private
*/
this.maxSlide_ = 0;
/**
* Whether the layout is going to be vertical or horizontal.
* @type {boolean}
*/
this.isVertical = this.el.classList.contains(CLASSES.VERTICAL);
/**
* Plugin's dictionary.
* @type {Object}
*/
this.plugins = {};
/**
* Interval ID reference for the autoslide.
* @type {?number}
* @private
*/
this.interval_ = null;
/**
* Amount of time to wait to go to next slide automatically or false to
* disable the feature.
* @type {boolean|number}
* @private
*/
this.autoslide_ = autoslide;
if (!this.el) {
throw new Error('Couldn\'t find the webslides container!');
}
// Bootstrapping
this.removeChildren_();
this.grabSlides_();
this.createPlugins_();
this.initSlides_();
this.play();
// Finished
this.onInit_();
}
/**
* Removes all children elements inside of the main container that are not
* eligible to be a Slide Element.
* @private
*/
removeChildren_() {
const nodes = this.el.childNodes;
let i = nodes.length;
while (i--) {
const node = nodes[i];
if (!Slide.isCandidate(node)) {
this.el.removeChild(node);
}
}
}
/**
* Creates all the registered plugins and store the instances inside of the
* the webslide instance.
* @private
*/
createPlugins_() {
Object.keys(PLUGINS).forEach(pluginName => {
const pluginCto = PLUGINS[pluginName];
this.plugins[pluginName] = new pluginCto(this);
});
}
/**
* Called once the WebSlide instance has finished initialising.
* @private
* @fires WebSlide#ws:init
*/
onInit_() {
DOM.fireEvent(this.el, 'ws:init');
}
/**
* Grabs the slides from the DOM and creates all the Slides modules.
* @private
*/
grabSlides_() {
this.slides = Array.from(this.el.childNodes)
.map((slide, i) => new Slide(slide, i));
this.maxSlide_ = this.slides.length;
}
/**
* Goes to a given slide.
* @param {!number} slideI The slide index.
* @param {?boolean} forward Whether we're forcing moving forward/backwards.
* This parameter is used only from the goNext, goPrev functions to adjust the
* scroll animations.
*/
goToSlide(slideI, forward = null) {
if (this.isValidIndexSlide_(slideI) && !this.isMoving) {
this.isMoving = true;
let isMovingForward = false;
if (forward !== null) {
isMovingForward = forward;
} else {
if (this.currentSlideI_ >= 0) {
isMovingForward = slideI > this.currentSlideI_;
}
}
const nextSlide = this.slides[slideI];
if (this.currentSlide_ !== null && this.isVertical &&
(!this.plugins.touch || !this.plugins.touch.isEnabled)) {
this.scrollTransitionToSlide_(
isMovingForward, nextSlide, this.onSlideChange_);
} else {
this.transitionToSlide_(
isMovingForward, nextSlide, this.onSlideChange_);
}
}
}
/**
* Transitions to a slide, doing the scroll animation.
* @param {boolean} isMovingForward Whether we're going forward or backwards.
* @param {Slide} nextSlide Next slide.
* @param {Function} callback Callback to be called upon finishing. This is an
* async function so it'll happen once the scroll animation finishes.
* @private
* @see DOM.lockScroll
* @see DOM.unlockScroll
* @see ScrollHelper.scrollTo
*/
scrollTransitionToSlide_(isMovingForward, nextSlide, callback) {
DOM.lockScroll();
if (!isMovingForward) {
nextSlide.moveBeforeFirst();
nextSlide.show();
ScrollHelper.scrollTo(this.currentSlide_.el.offsetTop, 0);
} else {
nextSlide.show();
}
ScrollHelper.scrollTo(nextSlide.el.offsetTop, 500, () => {
this.currentSlide_.hide();
if (isMovingForward) {
this.currentSlide_.moveAfterLast();
}
DOM.unlockScroll();
setTimeout(() => { callback.call(this, nextSlide); }, 150);
});
}
/**
* Transitions to a slide, without doing the scroll animation.
* @param {boolean} isMovingForward Whether we're going forward or backwards.
* @param {Slide} nextSlide Next slide.
* @param {Function} callback Callback to be called upon finishing. This is a
* sync function so it'll happen on run time.
* @private
*/
transitionToSlide_(isMovingForward, nextSlide, callback) {
ScrollHelper.scrollTo(0, 0);
if (!isMovingForward) {
nextSlide.moveBeforeFirst();
}
if (this.currentSlide_) {
if (isMovingForward) {
this.currentSlide_.moveAfterLast();
}
this.currentSlide_.hide();
}
nextSlide.show();
callback.call(this, nextSlide);
}
/**
* Whenever a slide is changed, this function gets called. It updates the
* references to the current slide, disables the moving flag and fires
* a custom event.
* @param {Slide} slide The slide we're transitioning to.
* @fires WebSlide#ws:slide-change
* @private
*/
onSlideChange_(slide) {
this.currentSlide_ = slide;
this.currentSlideI_ = slide.i;
this.isMoving = false;
DOM.fireEvent(this.el, 'ws:slide-change', {
slides: this.maxSlide_,
currentSlide0: this.currentSlideI_,
currentSlide: this.currentSlideI_ + 1
});
}
/**
* Goes to the next slide.
*/
goNext() {
let nextIndex = this.currentSlideI_ + 1;
if (nextIndex >= this.maxSlide_) {
nextIndex = 0;
}
this.goToSlide(nextIndex, true);
}
/**
* Goes to the previous slide.
*/
goPrev() {
let prevIndex = this.currentSlideI_ - 1;
if (prevIndex < 0) {
prevIndex = this.maxSlide_ - 1;
}
this.goToSlide(prevIndex, false);
}
/**
* Check if the given number is a valid index to go to.
* @param {number} i The index to check.
* @return {boolean} Whether you can move to that slide or not.
* @private
*/
isValidIndexSlide_(i) {
return i >= 0 && i < this.maxSlide_;
}
/**
* Init the shown slide on load. It'll fetch it from the Hash if present
* and, otherwise, it'll default to the first one.
* @private
* @see Hash.getSlideNumber
*/
initSlides_() {
let slideNumber = this.plugins.hash.constructor.getSlideNumber();
// Not valid
if (slideNumber === null ||
slideNumber >= this.maxSlide_) {
slideNumber = 0;
}
// Keeping the order
if (slideNumber !== 0) {
let i = 0;
while(i < slideNumber) {
this.slides[i].moveAfterLast();
i++;
}
}
this.goToSlide(slideNumber);
}
/**
* Registers a plugin to be loaded when the instance is created. It allows
* (on purpose) to replace default plugins.
* Those being:
* - Navigation
* - Hash
* - Keyboard
* @param {!string} key They key under which it'll be stored inside of the
* instance, inside the plugins dict.
* @param {!Function} cto Plugin constructor.
*/
static registerPlugin(key, cto) {
PLUGINS[key] = cto;
}
/**
* Starts autosliding all the slides if it's not currently doing it and the
* autoslide option was a number greater than 0.
* @param {?number} time Amount of milliseconds to wait to go to next slide
* automatically.
*/
play(time) {
time = time || this.autoslide_;
if (!this.interval_ && Number.isInteger(time) && time > 0) {
this.interval_ = setInterval(this.goNext.bind(this), time);
}
}
/**
* Stops autosliding all the slides.
*/
stop() {
if (this.interval_) {
clearInterval(this.interval_);
this.interval_ = null;
}
}
}

44
src/js/plugins/grid.js Normal file
View File

@@ -0,0 +1,44 @@
import Keys from '../utils/keys';
export default class Keyboard {
/**
* Grid plugin that shows a grid on top of the WebSlides for easy prototyping.
* @param {WebSlides} wsInstance The WebSlides instance
*/
constructor(wsInstance) {
/**
* @type {WebSlides}
* @private
*/
this.ws_ = wsInstance;
const CSS = `body.baseline {
background: url(../images/baseline.png) left top .8rem/.8rem;
}`;
const head = document.head || document.getElementsByTagName('head')[0];
const style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet){
style.styleSheet.cssText = CSS;
} else {
style.appendChild(document.createTextNode(CSS));
}
head.appendChild(style);
document.addEventListener('keydown', this.onKeyPress_.bind(this), false);
}
/**
* Reacts to the keydown event. It reacts to ENTER key to toggle the class.
* @param {KeyboardEvent} event The key event.
* @private
*/
onKeyPress_(event) {
if (event.which === Keys.ENTER) {
document.body.toggleClass('baseline');
}
}
}

71
src/js/plugins/hash.js Normal file
View File

@@ -0,0 +1,71 @@
const HASH = '#slide';
const slideRegex = /#slide=(\d+)/;
/**
* Static class with methods to manipulate and extract info from the hash of
* the URL.
*/
export default class Hash {
/**
* Listens to the slide change event and the hash change events.
* @param wsInstance
*/
constructor(wsInstance) {
this.ws_ = wsInstance;
wsInstance.el.addEventListener('ws:slide-change', Hash.onSlideChange_);
window.addEventListener('hashchange', this.onHashChange_.bind(this), false);
}
/**
* hashchange event handler, makes the WebSlide instance navigate to the
* needed slide.
*/
onHashChange_() {
const newSlideIndex = Hash.getSlideNumber();
if (newSlideIndex !== null) {
this.ws_.goToSlide(newSlideIndex);
}
}
static onSlideChange_(event) {
Hash.setSlideNumber(event.detail.currentSlide);
}
/**
* Gets the slide number from the hash by a regex matching `#slide=` and gets
* the number after it. If the number is invalid or less than 0, it will
* return null as an invalid value.
* @return {?number}
*/
static getSlideNumber() {
let results = document.location.hash.match(slideRegex);
let slide = 0;
if (Array.isArray(results)) {
slide = parseInt(results[1], 10);
}
if (!Number.isInteger(slide) || slide < 0 || !Array.isArray(results)) {
slide = null;
} else {
slide--; // Convert to 0 index
}
return slide;
}
/**
* It will update the hash (if it's different) so it reflects the slide
* number being visible.
* @param {number} number The number of the slide we're transitioning to.
*/
static setSlideNumber(number) {
if (Hash.getSlideNumber() !== (number - 1)) {
history.pushState({
slideI: number - 1
}, `Slide ${number}`, `${HASH}=${number}`);
}
}
}

View File

@@ -0,0 +1,49 @@
import Keys from '../utils/keys';
export default class Keyboard {
/**
* Keyboard interaction plugin.
* @param {WebSlides} wsInstance The WebSlides instance
*/
constructor(wsInstance) {
/**
* @type {WebSlides}
* @private
*/
this.ws_ = wsInstance;
document.addEventListener('keydown', this.onKeyPress_.bind(this), false);
}
/**
* Reacts to the keydown event. It reacts to the arrows and space key
* depending on the layout of the page.
* @param {KeyboardEvent} event The key event.
* @private
*/
onKeyPress_(event) {
let method;
if (event.which === Keys.SPACE) {
method = this.ws_.goNext;
} else {
if (this.ws_.isVertical) {
if (event.which === Keys.DOWN) {
method = this.ws_.goNext;
} else if (event.which === Keys.UP) {
method = this.ws_.goPrev;
}
} else {
if (event.which === Keys.RIGHT) {
method = this.ws_.goNext;
} else if (event.which === Keys.LEFT) {
method = this.ws_.goPrev;
}
}
}
if (method) {
method.call(this.ws_);
}
}
}

View File

@@ -0,0 +1,120 @@
import DOM from '../utils/dom';
const ELEMENT_ID = {
NAV: 'navigation',
NEXT: 'next',
PREV: 'previous',
COUNTER: 'counter'
};
const LABELS = {
VERTICAL: {
NEXT: '↓',
PREV: '↑'
},
HORIZONTAL: {
NEXT: '→',
PREV: '←'
}
};
export default class Navigation {
/**
* The Navigation constructor. It'll create all the nodes needed for the
* navigation such as the arrows and the counter.
* @param {WebSlides} wsInstance The WebSlides instance
*/
constructor(wsInstance) {
const arrowLabels = wsInstance.isVertical ?
LABELS.VERTICAL : LABELS.HORIZONTAL;
/**
* Navigation element.
* @type {Element}
*/
this.el = DOM.createNode('div', 'navigation');
/**
* Next button.
* @type {Element}
*/
this.next = Navigation.createArrow(ELEMENT_ID.NEXT, arrowLabels.NEXT);
/**
* Prev button.
* @type {Element}
*/
this.prev = Navigation.createArrow(ELEMENT_ID.PREV, arrowLabels.PREV);
/**
* Counter Element.
* @type {Element}
*/
this.counter = DOM.createNode('span', ELEMENT_ID.COUNTER);
/**
* @type {WebSlides}
* @private
*/
this.ws_ = wsInstance;
this.el.appendChild(this.next);
this.el.appendChild(this.prev);
this.el.appendChild(this.counter);
this.ws_.el.appendChild(this.el);
this.bindEvents_();
}
/**
* Bind all events for the navigation.
* @private
*/
bindEvents_() {
this.ws_.el.addEventListener(
'ws:slide-change', this.onSlideChanged_.bind(this));
this.next.addEventListener('click', this.onButtonClicked_.bind(this));
this.prev.addEventListener('click', this.onButtonClicked_.bind(this));
}
/**
* Updates the counter inside the navigation.
* @param {string|number} current Current slide number.
* @param {string|number} max Max slide number.
*/
updateCounter(current, max) {
this.counter.textContent = `${current} / ${max}`;
}
/**
* Creates an arrow to navigate.
* @param {!String} id Desired ID for the arrow.
* @param {!String} text Desired text for the arrow.
* @return {Element} The arrow element.
*/
static createArrow(id, text) {
const arrow = DOM.createNode('a', id, text);
arrow.href = '#';
arrow.title = 'Arrow Keys';
return arrow;
}
/**
* Slide Change event handler. Will update the text on the navigation.
* @param {CustomEvent} event
* @private
*/
onSlideChanged_(event) {
this.updateCounter(event.detail.currentSlide, event.detail.slides);
}
/**
* Handles clicks on the next/prev buttons.
* @param {MouseEvent} event
* @private
*/
onButtonClicked_(event) {
event.preventDefault();
if (event.target === this.next) {
this.ws_.goNext();
} else {
this.ws_.goPrev();
}
}
}

15
src/js/plugins/plugins.js Normal file
View File

@@ -0,0 +1,15 @@
import Grid from './grid';
import Hash from './hash';
import Keyboard from './keyboard';
import Navigation from './navigation';
import Scroll from './scroll';
import Touch from './touch';
export default {
Grid,
Hash,
Keyboard,
Navigation,
Scroll,
Touch
};

50
src/js/plugins/scroll.js Normal file
View File

@@ -0,0 +1,50 @@
import ScrollHelper from '../utils/scroll-to';
const MIN_WHEEL_DELTA = 40;
export default class Scroll {
/**
* Scroll handler for the WebSlides.
* @param {WebSlides} wsInstance The WebSlides instance
*/
constructor(wsInstance) {
/**
* @type {WebSlides}
* @private
*/
this.ws_ = wsInstance;
this.scrollContainer_ = ScrollHelper.getScrollableContainer();
this.isGoingUp_ = false;
if (this.ws_.isVertical) {
this.scrollContainer_.addEventListener(
'wheel', this.onMouseWheel_.bind(this));
}
}
/**
* Reacts to the wheel event. Detects whether is going up or down and decides
* if it needs to move the slide based on the amount of delta.
* @param {WheelEvent} event The Wheel Event.
* @private
*/
onMouseWheel_(event) {
if (this.ws_.isMoving) {
return;
}
const { deltaY: wheelDelta } = event;
this.isGoingUp_ = wheelDelta < 0;
if (Math.abs(wheelDelta) >= MIN_WHEEL_DELTA) {
if (this.isGoingUp_) {
this.ws_.goPrev();
} else {
this.ws_.goNext();
}
event.preventDefault();
}
}
};

151
src/js/plugins/touch.js Normal file
View File

@@ -0,0 +1,151 @@
import MobileDetector from '../utils/mobile-detector';
const EVENTS = {
touch: {
START: 'touchstart',
MOVE: 'touchmove',
END: 'touchend'
},
pointer: {
START: 'pointerdown',
MOVE: 'pointermove',
END: 'pointerup'
}
};
const SLIDE_OFFSET = 50;
export default class Touch {
/**
* @param {WebSlides} wsInstance The WebSlides instance
*/
constructor(wsInstance) {
/**
* @type {WebSlides}
* @private
*/
this.ws_ = wsInstance;
/**
* Start position for the X coord.
* @type {number}
* @private
*/
this.startX_ = 0;
/**
* Start position for the Y coord.
* @type {number}
* @private
*/
this.startY_ = 0;
/**
* Start position for the X coord.
* @type {number}
* @private
*/
this.endX_ = 0;
/**
* Start position for the Y coord.
* @type {number}
* @private
*/
this.endY_ = 0;
/**
* Whether is enabled or not. Only enabled for touch devices.
* @type {boolean}
* @private
*/
this.isEnabled = false;
let events;
if (MobileDetector.isAny()) {
// Likely IE
if (window.PointerEvent && (
MobileDetector.isWindows() || MobileDetector.isWindowsPhone())) {
events = EVENTS.pointer;
} else {
events = EVENTS.touch;
}
this.isEnabled = true;
document.addEventListener(events.START, this.onStart_.bind(this), false);
document.addEventListener(events.MOVE, this.onMove_.bind(this), false);
document.addEventListener(events.MOVE, this.onMove_.bind(this), false);
document.addEventListener(events.END, this.onStop_.bind(this), false);
}
}
/**
* Start touch handler. Saves starting points.
* @param event
* @private
*/
onStart_(event) {
const info = Touch.normalizeEventInfo(event);
this.startX_ = info.x;
this.startY_ = info.y;
this.endX_ = info.x;
this.endY_ = info.y;
}
/**
* Move touch handler. Saves end points.
* @param event
* @private
*/
onMove_(event) {
const info = Touch.normalizeEventInfo(event);
this.endX_ = info.x;
this.endY_ = info.y;
}
/**
* Stop touch handler. Checks if it needs to make any actions.
* @private
*/
onStop_() {
const diffX = this.startX_ - this.endX_;
const diffY = this.startY_ - this.endY_;
// It's an horizontal drag
if (Math.abs(diffX) > Math.abs(diffY)) {
if(diffX < -SLIDE_OFFSET) {
this.ws_.goPrev();
} else if(diffX > SLIDE_OFFSET) {
this.ws_.goNext();
}
}
}
/**
* Normalizes an event to deal with differences between PointerEvent and
* TouchEvent.
* @param event
* @return {*}
*/
static normalizeEventInfo(event) {
let x;
let y;
let touchEvent = { pageX : 0, pageY : 0};
if (typeof event.changedTouches !== 'undefined'){
touchEvent = event.changedTouches[0];
}
else if (typeof event.originalEvent !== 'undefined' &&
typeof event.originalEvent.changedTouches !== 'undefined'){
touchEvent = event.originalEvent.changedTouches[0];
}
x = event.offsetX || event.layerX || touchEvent.pageX;
y = event.offsetY || event.layerY || touchEvent.pageY;
return { x, y };
}
};

View File

@@ -0,0 +1,38 @@
const NativeCustomEvent = window.CustomEvent;
/**
* Check for the usage of native support for CustomEvents which is lacking
* completely on IE.
* @return {boolean} Whether it can be used or not.
*/
function canIuseNativeCustom () {
try {
const p = new NativeCustomEvent('t', { detail: { a: 'b' } });
return 't' === p.type && 'b' === p.detail.a;
} catch (e) {
}
return false;
}
/**
* Lousy polyfill for the Custom Event constructor for IE.
* @param {!string} type The type of the event.
* @param {?Object} params Additional information for the event.
* @return {Event}
* @constructor
*/
const IECustomEvent = function CustomEvent(type, params) {
const e = document.createEvent('CustomEvent');
if (params) {
e.initCustomEvent(type, params.bubbles, params.cancelable, params.detail);
} else {
e.initCustomEvent(type, false, false, undefined);
}
return e;
};
const WSCustomEvent = canIuseNativeCustom() ? NativeCustomEvent : IECustomEvent;
export default WSCustomEvent;

75
src/js/utils/dom.js Normal file
View File

@@ -0,0 +1,75 @@
import WSCustomEvent from './custom-event';
/**
* Static class for DOM helper.
*/
export default class DOM {
/**
* Creates a node with optional parameters.
* @param {string} tag The name of the tag of the needed element.
* @param {string} id The desired id for the element. It defaults to an
* empty string.
* @param {string} text The desired text to go inside of the element. It defaults
* to an empty string.
* @return {Element}
*/
static createNode(tag, id = '', text = '') {
const node = document.createElement(tag);
node.id = id;
if (text) {
node.textContent = text;
}
return node;
}
/**
* Hides an element setting the display to none.
* @param {Element} el Element to be hidden.
*/
static hide(el) {
el.style.display = 'none';
}
/**
* Shows an element by removing the display property. This is only intended
* to be used in conjunction with DOM.hide.
* @param {Element} el Element to be shown.
*/
static show(el) {
el.style.display = '';
}
/**
* Locks the scroll on the document by setting the HTML to have a hidden
* overflow.
*/
static lockScroll() {
document.documentElement.style.overflow = 'hidden';
}
/**
* Unlocks the scroll on the document by setting the HTML to have an auto
* overflow.
*/
static unlockScroll() {
document.documentElement.style.overflow = 'auto';
}
/**
* Fires a custom event on the given target.
* @param {Element} target The target of the event.
* @param {string} eventType The event type.
* @param {Object} eventInfo Optional parameter to provide additional data
* to the event.
*/
static fireEvent(target, eventType, eventInfo = {}) {
const event = new WSCustomEvent(eventType, {
detail: eventInfo
});
target.dispatchEvent(event);
}
}

19
src/js/utils/easing.js Normal file
View File

@@ -0,0 +1,19 @@
/**
* Swing easing function.
* @param {number} p The percentage of time that has passed.
* @return {number}
*/
function swing (p) {
return 0.5 - Math.cos(p * Math.PI) / 2;
}
/**
* Linear easing function.
* @param {number} p The percentage of time that has passed.
* @return {number}
*/
function linear(p) {
return p;
}
export default { swing, linear };

10
src/js/utils/keys.js Normal file
View File

@@ -0,0 +1,10 @@
const Keys = {
ENTER: 13,
SPACE: 32,
LEFT: 37,
UP: 38,
RIGHT: 39,
DOWN: 40
};
export default Keys;

View File

@@ -0,0 +1,64 @@
const UA = window.navigator.userAgent;
export default class MobileDetector {
/**
* Whether the device is Android or not.
* @return {Boolean}
*/
static isAndroid() {
return !!UA.match(/Android/i);
}
/**
* Whether the device is BlackBerry or not.
* @return {Boolean}
*/
static isBlackBerry() {
return !!UA.match(/BlackBerry/i);
}
/**
* Whether the device is iOS or not.
* @return {Boolean}
*/
static isiOS() {
return !!UA.match(/iPhone/i);
}
/**
* Whether the device is Opera or not.
* @return {Boolean}
*/
static isOpera() {
return !!UA.match(/Opera Mini/i);
}
/**
* Whether the device is Windows or not.
* @return {Boolean}
*/
static isWindows() {
return !!UA.match(/IEMobile/i);
}
/**
* Whether the device is Windows Phone or not.
* @return {Boolean}
*/
static isWindowsPhone() {
return !!UA.match(/Windows Phone/i);
}
/**
* Whether the device is any mobile device or not.
* @return {Boolean}
*/
static isAny() {
return MobileDetector.isAndroid() ||
MobileDetector.isBlackBerry() ||
MobileDetector.isiOS() ||
MobileDetector.isOpera() ||
MobileDetector.isWindows() ||
MobileDetector.isWindowsPhone();
}
}

74
src/js/utils/scroll-to.js Normal file
View File

@@ -0,0 +1,74 @@
import Easings from './easing';
let SCROLLABLE_CONTAINER = getScrollableContainer();
/**
* Returns the correct DOM element to be used for scrolling the
* page, due to Firefox not scrolling on document.body.
* @return {Element} Scrollable Element.
*/
function getScrollableContainer() {
if (SCROLLABLE_CONTAINER) {
return SCROLLABLE_CONTAINER;
}
const documentElement = window.document.documentElement;
let scrollableContainer;
documentElement.scrollTop = 1;
if (documentElement.scrollTop === 1) {
documentElement.scrollTop = 0;
scrollableContainer = documentElement;
} else {
scrollableContainer = document.body;
}
SCROLLABLE_CONTAINER = scrollableContainer;
return scrollableContainer;
}
/**
* Smoothly scrolls to a given Y position using Easing.Swing. It'll run a
* callback upon finishing.
* @param {number} y Offset of the page to scroll to.
* @param {number} duration Duration of the animation. 500ms by default.
* @param {function} cb Callback function to call upon completion.
*/
function scrollTo(y, duration = 500, cb = () => {}) {
const scrollableContainer = getScrollableContainer();
const delta = y - scrollableContainer.scrollTop;
const startLocation = scrollableContainer.scrollTop;
const increment = 16;
if (!duration) {
scrollableContainer.scrollTop = y;
cb();
return;
}
const animateScroll = elapsedTime => {
elapsedTime += increment;
const percent = Math.min(1, elapsedTime / duration);
const easingP = Easings.swing(
percent,
elapsedTime * percent,
y,
delta,
duration);
scrollableContainer.scrollTop = Math.floor(startLocation +
(easingP * delta));
if (elapsedTime < duration) {
setTimeout(() => animateScroll(elapsedTime), increment);
} else {
cb();
}
};
animateScroll(0);
}
export default { getScrollableContainer, scrollTo };

View File

@@ -1,9 +1,9 @@
/*--------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------
App: WebSlides App: WebSlides
Version: 0.1.1 Version: 1.0.0
Date: 2017-02-11 Date: 2017-02-11
Description: A simple and versatile framework for building HTML presentations, landings, and portfolios. Description: A simple and versatile framework for building HTML presentations, landings, and portfolios.
Author: José Luis Antúnez Author: José Luis Antúnez
Author URI: http://twitter.com/jlantunez Author URI: http://twitter.com/jlantunez
License: The MIT License (MIT) License: The MIT License (MIT)
@@ -23,11 +23,11 @@
2.3 San Francisco Font (Apple) 2.3 San Francisco Font (Apple)
3. Header & Footer 3. Header & Footer
3.1 Logo 3.1 Logo
4. Navigation 4. Navigation
4.1 Navbars 4.1 Navbars
5. SLIDES (vertically and horizontally centered) 5. SLIDES (vertically and horizontally centered)
5.1 Mini container & Alignment 5.1 Mini container & Alignment
5.2 Counter / Navigation Slides 5.2 Counter / Navigation Slides
5.3 Background Images/Video 5.3 Background Images/Video
6. Magic blocks = .flexblock (Flexible blocks with auto-fill and equal height). 6. Magic blocks = .flexblock (Flexible blocks with auto-fill and equal height).
6.1 .flexblock.features 6.1 .flexblock.features
@@ -56,11 +56,11 @@
0. CSS Reset & Normalize 0. CSS Reset & Normalize
=========================================== */ =========================================== */
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, bbbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { border: 0; font-size: 100%; font: inherit; vertical-align: baseline; margin: 0; padding: 0 } html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, bbbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { border: 0; font-size: 100%; font: inherit; vertical-align: baseline; margin: 0; padding: 0 }
article, aside, details, figcaption, figure, footer, header, main, menu, nav, section, summary { article, aside, details, figcaption, figure, footer, header, main, menu, nav, section, summary {
display: block; display: block;
} }
body { body {
line-height: 1; line-height: 1;
} }
@@ -215,7 +215,7 @@ ins {
text-decoration: none; text-decoration: none;
padding: 0 4px; padding: 0 4px;
text-shadow: none; text-shadow: none;
} }
::-moz-selection { ::-moz-selection {
@@ -291,7 +291,7 @@ dd {
/*=== Clearing === */ /*=== Clearing === */
.clear:before, .clear:after, header:before, header:after, main:before, main:after, .wrap:before, .wrap:after, group:before, group:after, section:before, section:after, aside:before, aside:after,footer:before, footer:after{ content: ""; display: table; } .clear:before, .clear:after, header:before, header:after, main:before, main:after, .wrap:before, .wrap:after, group:before, group:after, section:before, section:after, aside:before, aside:after,footer:before, footer:after{ content: ""; display: table; }
.clear:after, header:after, main:after, .wrap:after, group:after, section:after, aside:after, footer:after { clear: both; } .clear:after, header:after, main:after, .wrap:after, group:after, section:after, aside:after, footer:after { clear: both; }
/*========================================= /*=========================================
@@ -302,7 +302,7 @@ body {
overflow-x: hidden; overflow-x: hidden;
} }
/* == Prototype faster - Vertical rhythm == */ /* == Prototype faster - Vertical rhythm == */
body.baseline { body.baseline {
background: url(../images/baseline.png) left top .8rem/.8rem; background: url(../images/baseline.png) left top .8rem/.8rem;
@@ -343,7 +343,7 @@ nav a[rel="external"] em,
/*Layer/Box Shadow*/ /*Layer/Box Shadow*/
.shadow { .shadow {
position: relative; position: relative;
} }
.shadow:before,.shadow:after { .shadow:before,.shadow:after {
z-index: -1; z-index: -1;
@@ -472,8 +472,8 @@ pre code {
padding: 0; padding: 0;
} }
/*=== 1.2 Animations ================ /*=== 1.2 Animations ================
Just 3 basic animations: Just 3 basic animations:
.fadeIn, .fadeInUp, .zoomIn. .fadeIn, .fadeInUp, .zoomIn.
https://github.com/daneden/animate.css*/ https://github.com/daneden/animate.css*/
@@ -674,9 +674,9 @@ li .browser {margin-bottom: 0;
content: "● ● ●"; content: "● ● ●";
} }
@media (min-width:768px) { @media (min-width:768px) {
.browser:before { .browser:before {
font-size: 1.6rem; font-size: 1.6rem;
} }
} }
@@ -718,7 +718,7 @@ Auto-fill & Equal height === */
-webkit-flex-direction: column; -webkit-flex-direction: column;
flex-direction: column; flex-direction: column;
-webkit-transition: .3s; -webkit-transition: .3s;
transition: .3s; transition: .3s;
padding: 2.4rem; padding: 2.4rem;
} }
@@ -732,21 +732,21 @@ Auto-fill & Equal height === */
} }
/* Grid (Sidebar + Main) .grid.sm */ /* Grid (Sidebar + Main) .grid.sm */
.grid.sm .column:nth-child(1) { .grid.sm .column:nth-child(1) {
width: 30% width: 30%
} }
.grid.sm .column:nth-child(2) { .grid.sm .column:nth-child(2) {
width: 70%; width: 70%;
} }
/* Grid (Main + Sidebar) .grid.ms */ /* Grid (Main + Sidebar) .grid.ms */
.grid.ms .column:nth-child(1) { .grid.ms .column:nth-child(1) {
width: 70% width: 70%
} }
.grid.ms .column:nth-child(2) { .grid.ms .column:nth-child(2) {
width: 30%; width: 30%;
} }
/* Grid (Sidebar + Main + Sidebar) .grid.sms */ /* Grid (Sidebar + Main + Sidebar) .grid.sms */
.grid.sms .column:nth-child(2) { .grid.sms .column:nth-child(2) {
width: 50%; width: 50%;
} }
} }
@@ -807,7 +807,7 @@ ul.description {
} }
.description + p{ .description + p{
margin-top: 3.2rem; margin-top: 3.2rem;
} }
.description li { .description li {
@@ -818,7 +818,7 @@ margin-top: 3.2rem;
transition: .3s; transition: .3s;
} }
.description li:hover{ .description li:hover{
padding-left: .4rem; padding-left: .4rem;
} }
ul.description li,.column ul li {list-style: none;margin-left: 0;} ul.description li,.column ul li {list-style: none;margin-left: 0;}
@@ -830,7 +830,7 @@ h2 svg, h3 svg, h4 svg {
margin-top: -.8rem; margin-top: -.8rem;
} }
.text-intro svg,.wall p svg,.try svg { .text-intro svg,.wall p svg,.try svg {
margin-top: -.4rem; margin-top: -.4rem;
} }
.flexblock li h2 svg,.flexblock li h3 svg {margin-top: 0; .flexblock li h2 svg,.flexblock li h3 svg {margin-top: 0;
} }
@@ -908,10 +908,10 @@ h1+img,h2+img,h3+img {
[class*="content-"] > [class*="content-"] h2, [class*="content-"] > [class*="content-"] h2,
[class*="content-"] > [class*="content-"] h3, [class*="content-"] > [class*="content-"] h3,
[class*="content-"] > [class*="content-"] h4 { [class*="content-"] > [class*="content-"] h4 {
font-size: 2.4rem; font-size: 2.4rem;
line-height: 4rem; line-height: 4rem;
} }
/*========================================= /*=========================================
2.1. Headings with background 2.1. Headings with background
=========================================== */ =========================================== */
@@ -922,11 +922,11 @@ li[class*="bg-"],p[class*="bg-"] {
} }
h1 [class*="bg-"],h2 [class*="bg-"],h3 [class*="bg-"] { h1 [class*="bg-"],h2 [class*="bg-"],h3 [class*="bg-"] {
padding: .4rem .8rem; padding: .4rem .8rem;
} }
/*========================================= /*=========================================
2.2. Typography Classes = .text- 2.2. Typography Classes = .text-
=========================================== */ =========================================== */
.text-intro,[class*="content-"] p { .text-intro,[class*="content-"] p {
@@ -948,9 +948,9 @@ padding: .4rem .8rem;
@media (min-width: 768px) { @media (min-width: 768px) {
.text-landing { .text-landing {
letter-spacing: 1.6rem; letter-spacing: 1.6rem;
} }
} }
/* -- Subtitle (Before h1, h2) -- /* -- Subtitle (Before h1, h2) --
p.subtitle + h1/h2 */ p.subtitle + h1/h2 */
p.text-subtitle { p.text-subtitle {
@@ -996,7 +996,7 @@ p.text-subtitle svg {vertical-align: text-top;}
/* -- Magazine Two Columns -- */ /* -- Magazine Two Columns -- */
@media (min-width: 768px) { @media (min-width: 768px) {
.text-cols { .text-cols {
-webkit-column-count: 2; -webkit-column-count: 2;
-moz-column-count: 2; -moz-column-count: 2;
column-count: 2; column-count: 2;
@@ -1004,10 +1004,10 @@ p.text-subtitle svg {vertical-align: text-top;}
-moz-column-gap: 4.8rem; -moz-column-gap: 4.8rem;
column-gap: 4.8rem; column-gap: 4.8rem;
text-align: left; text-align: left;
} }
.text-landing + .text-cols{ .text-landing + .text-cols{
margin-top: 3.2rem; margin-top: 3.2rem;
} }
} }
.text-cols p:first-child:first-letter { .text-cols p:first-child:first-letter {
font-size: 11rem; font-size: 11rem;
@@ -1037,7 +1037,7 @@ margin-top: 3.2rem;
margin-bottom: .6rem; margin-bottom: .6rem;
} }
.column .text-context:before { .column .text-context:before {
width:100%; width:100%;
} }
/* -- Separator/Symbols (stars ***...) -- */ /* -- Separator/Symbols (stars ***...) -- */
@@ -1047,63 +1047,63 @@ width:100%;
/* -- Separator -- */ /* -- Separator -- */
.text-separator { .text-separator {
margin-top:2.4rem; margin-top:2.4rem;
} }
.text-separator:before { .text-separator:before {
position: absolute; position: absolute;
width: 16%; width: 16%;
height: .4rem; height: .4rem;
content: ""; content: "";
margin-top:-1.6rem; margin-top:-1.6rem;
left: 0; left: 0;
} }
@media (min-width: 568px) { @media (min-width: 568px) {
.text-separator { .text-separator {
width: 80%; width: 80%;
margin-top: 0; margin-top: 0;
margin-left: 20%; margin-left: 20%;
} }
.text-separator:before { .text-separator:before {
margin-top: 1.2rem; margin-top: 1.2rem;
} }
} }
/* -- Pull Quote (Right/Left) -- */ /* -- Pull Quote (Right/Left) -- */
[class*="text-pull"] { [class*="text-pull"] {
position: relative; position: relative;
font-size: 2.4rem; font-size: 2.4rem;
line-height: 4rem; line-height: 4rem;
font-weight: 400; font-weight: 400;
margin-right: 2.4rem; margin-right: 2.4rem;
margin-left: 2.4rem; margin-left: 2.4rem;
} }
[class*="text-pull-"] { [class*="text-pull-"] {
padding-top: 1.4rem; padding-top: 1.4rem;
margin-top: .8rem; margin-top: .8rem;
} }
@media (min-width: 1024px) { @media (min-width: 1024px) {
[class*="text-pull"] { [class*="text-pull"] {
margin-right: -4rem; margin-right: -4rem;
margin-left: -4rem; margin-left: -4rem;
} }
} }
@media (min-width: 568px) { @media (min-width: 568px) {
[class*="text-pull-"] { [class*="text-pull-"] {
width: 32rem; width: 32rem;
} }
.text-pull-right { .text-pull-right {
float: right; float: right;
margin-right: -2.4rem; margin-right: -2.4rem;
margin-left: 2.4rem; margin-left: 2.4rem;
} }
.text-pull-left { .text-pull-left {
float: left; float: left;
margin-left: -2.4rem; margin-left: -2.4rem;
margin-right: 2.4rem; margin-right: 2.4rem;
} }
} }
/* -- Info Messages (error, warning, success... -- */ /* -- Info Messages (error, warning, success... -- */
@@ -1111,8 +1111,8 @@ margin-right: 2.4rem;
} }
/*========================================= /*=========================================
2.1. San Francisco Font (Apple's new font) 2.1. San Francisco Font (Apple's new font)
=========================================== */ =========================================== */
.text-apple,.bg-apple { .text-apple,.bg-apple {
@@ -1169,8 +1169,8 @@ footer,
header p, header p,
footer p { footer p {
line-height: 4.8rem; line-height: 4.8rem;
margin-bottom: 0; margin-bottom: 0;
} }
header[role=banner] img, header[role=banner] img,
@@ -1197,7 +1197,7 @@ section footer {
/*desktop only? Add @media (min-width: 1025px)*/ /*desktop only? Add @media (min-width: 1025px)*/
header[role=banner] { header[role=banner] {
opacity: 0; opacity: 0;
} }
/*=== Show Header[role=banner] === */ /*=== Show Header[role=banner] === */
header[role=banner]:hover { header[role=banner]:hover {
@@ -1205,10 +1205,10 @@ header[role=banner]:hover {
} }
@media (max-width: 767px) { @media (max-width: 767px) {
footer .alignleft, footer .alignright { footer .alignleft, footer .alignright {
float: none; float: none;
display: block; display: block;
} }
} }
@@ -1250,7 +1250,7 @@ nav ul {
display: flex; display: flex;
-webkit-flex-wrap: wrap; -webkit-flex-wrap: wrap;
flex-wrap: wrap; flex-wrap: wrap;
/*====align left====*/ /*====align left====*/
justify-content: flex-start; justify-content: flex-start;
/* ==== align center ====*/ /* ==== align center ====*/
/*justify-content: center; */ /*justify-content: center; */
@@ -1297,37 +1297,38 @@ nav.aligncenter ul, .aligncenter nav ul {
} }
nav.navbar ul li { nav.navbar ul li {
/*====full float li a ====*/ /*====full float li a ====*/
-webkit-flex: 1 1 auto; -webkit-flex: 1 1 auto;
flex: 1 1 auto; flex: 1 1 auto;
} }
@media (max-width: 568px) { @media (max-width: 568px) {
nav.navbar ul { nav.navbar ul {
-webkit-flex-flow: column wrap; -webkit-flex-flow: column wrap;
flex-flow: column wrap; flex-flow: column wrap;
padding: 0; padding: 0;
} }
nav.navbar li a{justify-content:flex-start; nav.navbar li a {
} justify-content:flex-start;
}
} }
/*============================================ /*============================================
5. SLIDES (Full Screen) 5. SLIDES (Full Screen)
Vertically and horizontally centered Vertically and horizontally centered
============================================== */ ============================================== */
/* Fade transition to all slides. /* Fade transition to all slides.
* = All HTML elements will have those styles.*/ * = All HTML elements will have those styles.*/
section * { section * {
-webkit-animation: fadeIn 0.3s ease-in-out; -webkit-animation: fadeIn 0.3s ease-in-out;
animation: fadeIn 0.3s ease-in-out; animation: fadeIn 0.3s ease-in-out;
} }
section .background,section .background-video, section .background,section .background-video,
[class*="background-"].light,[class*="background-"].dark { [class*="background-"].light,[class*="background-"].dark {
-webkit-animation-duration:0s; -webkit-animation-duration:0s;
animation-duration:0s; animation-duration:0s;
} }
/*=== Section = Slide === */ /*=== Section = Slide === */
@@ -1349,17 +1350,17 @@ section,.slide
} }
@media (min-width: 1024px) { @media (min-width: 1024px) {
section, .slide { section, .slide {
padding-top: 12rem; padding-top: 12rem;
padding-bottom: 12rem; padding-bottom: 12rem;
} }
} }
/*slide no padding (full card, .embed> youtube video...) */ /*slide no padding (full card, .embed> youtube video...) */
.fullscreen { .fullscreen {
padding: 0; padding: 0;
/* Fixed/Visible header? /* Fixed/Visible header?
padding:8.2rem 0 0 0; padding:8.2rem 0 0 0;
*/ */
} }
/* slide alignment - top */ /* slide alignment - top */
@@ -1374,7 +1375,7 @@ padding:8.2rem 0 0 0;
} }
/*== 5.1. Mini container width:50% (600px) /*== 5.1. Mini container width:50% (600px)
.wrap:1200px; / Aligned items [class*="content-"]=== */ .wrap:1200px; / Aligned items [class*="content-"]=== */
[class*="content-"] { [class*="content-"] {
@@ -1385,12 +1386,12 @@ padding:8.2rem 0 0 0;
.wrap[class*="bg-"],.wrap.frame, .wrap[class*="bg-"],.wrap.frame,
[class*="content-"][class*="bg-"], [class*="content-"][class*="bg-"],
[class*="content-"].frame, [class*="align"][class*="bg-"]{ [class*="content-"].frame, [class*="align"][class*="bg-"]{
padding: 4.8rem; padding: 4.8rem;
} }
[class*="content-"] > [class*="content-"] p { [class*="content-"] > [class*="content-"] p {
font-size: 1.8rem; font-size: 1.8rem;
line-height: 3.2rem; line-height: 3.2rem;
} }
.content-center { .content-center {
@@ -1399,7 +1400,7 @@ padding:8.2rem 0 0 0;
} }
@media (min-width: 768px) { @media (min-width: 768px) {
[class*="content-"] { [class*="content-"] {
width: 50%; width: 50%;
} }
.content-left { .content-left {
@@ -1408,45 +1409,45 @@ padding:8.2rem 0 0 0;
.content-right { .content-right {
float: right; float: right;
} }
[class*="content-"] + [class*="content-"] { [class*="content-"] + [class*="content-"] {
padding-left:2.4rem; padding-left:2.4rem;
margin-bottom: 4.8rem; margin-bottom: 4.8rem;
} }
[class*="content-"] + [class*="size-"] { [class*="content-"] + [class*="size-"] {
margin-top: 6.4rem; margin-top: 6.4rem;
clear:both; clear:both;
} }
[class*="content-"]:before, [class*="content-"]:before,
[class*="content-"]:after { [class*="content-"]:after {
content: ""; content: "";
display: table; display: table;
} }
[class*="content-"]:after { [class*="content-"]:after {
clear: both; clear: both;
} }
} }
/* === 5.2 Counter / Navigation Slides === */ /* === 5.2 Counter / Navigation Slides === */
#navigation { #navigation {
position: fixed; position: fixed;
width: 24.4rem; width: 24.4rem;
margin-right: auto; margin-right: auto;
margin-left: auto; margin-left: auto;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
/* hover/visibility */ /* hover/visibility */
z-index: 3; z-index: 3;
} }
#navigation { #navigation {
-webkit-animation: fadeIn 16s; -webkit-animation: fadeIn 16s;
animation: fadeIn 16s; animation: fadeIn 16s;
opacity:0; opacity:0;
} }
#navigation:hover { #navigation:hover {
opacity: 1; opacity: 1;
} }
/* -- navigation arrow always visible? -- */ /* -- navigation arrow always visible? -- */
@@ -1489,14 +1490,14 @@ a#previous {
left: 3.2rem; left: 3.2rem;
} }
@media (max-width:1024px) { @media (max-width:1024px) {
#navigation { #navigation {
background: url('../images/swipe.svg') no-repeat center top; background: url('../images/swipe.svg') no-repeat center top;
background-size: 4.8rem; background-size: 4.8rem;
-webkit-animation: fadeIn 6s; -webkit-animation: fadeIn 6s;
animation: fadeIn 6s; animation: fadeIn 6s;
} }
#navigation a, #counter {display: none; #navigation a, #counter {display: none;
} }
} }
/*=== 5.3 Slides - Background Images === */ /*=== 5.3 Slides - Background Images === */
@@ -1516,15 +1517,15 @@ animation: fadeIn 6s;
background-size: cover background-size: cover
} }
.background-top { .background-top {
background-position: top; background-position: top;
background-size: cover; background-size: cover;
} }
.background-bottom { .background-bottom {
background-position: bottom; background-position: bottom;
background-size: cover; background-size: cover;
} }
/*fullscreen video /*fullscreen video
<video class="background-video"> <video class="background-video">
*/ */
@@ -1544,10 +1545,10 @@ background-size: cover;
background-position: center top; background-position: center top;
} }
.background-right-top { .background-right-top {
background-position: right top; background-position: right top;
} }
.background-left-top { .background-left-top {
background-position: left top; background-position: left top;
} }
.background-center-bottom, .background-center-bottom,
.background-left-bottom, .background-left-bottom,
@@ -1556,8 +1557,8 @@ background-size: cover;
background-position: center bottom; background-position: center bottom;
} }
@media (min-width:1024px) { @media (min-width:1024px) {
.background-left-bottom { .background-left-bottom {
background-position: left bottom; background-position: left bottom;
} }
.background-right-bottom { .background-right-bottom {
@@ -1594,14 +1595,14 @@ background-size: cover;
filter: alpha(opacity=5); filter: alpha(opacity=5);
} }
@media (max-width:1023px) { @media (max-width:1023px) {
[class*="background-"] { [class*="background-"] {
opacity: 0.20; opacity: 0.20;
-webkit-animation: fadeIn ease-in 0.20; -webkit-animation: fadeIn ease-in 0.20;
animation: fadeIn ease-in 0.20; animation: fadeIn ease-in 0.20;
} }
.background-video { .background-video {
opacity: 0.80; opacity: 0.80;
} }
} }
/*=== Animated Background Image === */ /*=== Animated Background Image === */
@@ -1612,11 +1613,11 @@ background-size: cover;
background-position: center top; background-position: center top;
-webkit-animation: anim 80s linear infinite; -webkit-animation: anim 80s linear infinite;
animation: anim 80s linear infinite; animation: anim 80s linear infinite;
} }
/*=============================================================== /*===============================================================
6. Magic blocks with flexbox (Auto-fill & Equal Height) 6. Magic blocks with flexbox (Auto-fill & Equal Height)
Blocks Links li>a = .flexblock.blink (.blink required) Blocks Links li>a = .flexblock.blink (.blink required)
================================================================= */ ================================================================= */
@@ -1662,8 +1663,8 @@ Blocks Links li>a = .flexblock.blink (.blink required)
transition: .3s; transition: .3s;
} }
.flexblock li:hover{ .flexblock li:hover{
-webkit-transform: translateY(-.2rem); -webkit-transform: translateY(-.2rem);
transform: translateY(-.2rem); transform: translateY(-.2rem);
} }
.flexblock.aligncenter li {text-align: center;} .flexblock.aligncenter li {text-align: center;}
@@ -1729,9 +1730,9 @@ div + ul, div + ol{
width: 46%; width: 46%;
} }
.column .flexblock.features>li{width: 100%;} .column .flexblock.features>li{width: 100%;}
footer .flexblock.features>li {margin-bottom: 0; footer .flexblock.features>li {margin-bottom: 0;
} }
} }
@@ -1751,15 +1752,15 @@ div + ul, div + ol{
display: block; display: block;
} }
.features li span,.features li svg { .features li span,.features li svg {
font-size: 6.4rem; font-size: 6.4rem;
line-height: 1; line-height: 1;
display: block; display: block;
margin: 0; margin: 0;
} }
.features li img {width: 6.4rem;} .features li img {width: 6.4rem;}
.features li span sup { .features li span sup {
font-size: 3rem; font-size: 3rem;
} }
@media (min-width:1200px) { @media (min-width:1200px) {
@@ -1803,7 +1804,7 @@ div + ul, div + ol{
} }
.clients li:hover { .clients li:hover {
z-index: 1; z-index: 1;
} }
/*================================================== /*==================================================
6.3 flexblock.steps <ul class="flexblock steps"> 6.3 flexblock.steps <ul class="flexblock steps">
@@ -1905,20 +1906,20 @@ About, Philosophy...
} }
.specs li span,.specs li svg { .specs li span,.specs li svg {
font-size: 6.4rem; font-size: 6.4rem;
line-height: 1; line-height: 1;
display: block; display: block;
margin: 0; margin: 0;
} }
.specs li img {width: 6.4rem;} .specs li img {width: 6.4rem;}
.specs li span { .specs li span {
font-weight: 300; font-weight: 300;
} }
.specs li span sup { .specs li span sup {
font-size: 3rem; font-size: 3rem;
} }
@media (min-width:1024px) { @media (min-width:1024px) {
@@ -1934,18 +1935,18 @@ About, Philosophy...
=================================================== */ =================================================== */
.flexblock.reasons li { .flexblock.reasons li {
text-align: left; text-align: left;
width: 100%; width: 100%;
counter-increment: list; counter-increment: list;
} }
.reasons li:hover{ .reasons li:hover{
-webkit-transform: translateY(-.2rem); -webkit-transform: translateY(-.2rem);
transform: translateY(-.2rem); transform: translateY(-.2rem);
} }
.reasons li:before { .reasons li:before {
content: counter(list)'.'; content: counter(list)'.';
font-size: 6.4rem; font-size: 6.4rem;
line-height: 1; line-height: 1;
} }
.reasons li:after { .reasons li:after {
position: relative; position: relative;
@@ -1955,12 +1956,12 @@ transform: translateY(-.2rem);
display: block; display: block;
} }
@media (min-width: 768px) { @media (min-width: 768px) {
.reasons li { .reasons li {
padding-left: 8.8rem; padding-left: 8.8rem;
/* You need two digits? (1-10)*/ /* You need two digits? (1-10)*/
/*padding-left: 12rem; */ /*padding-left: 12rem; */
} }
.reasons li:before { .reasons li:before {
position: absolute; position: absolute;
left: 2.4rem; left: 2.4rem;
} }
@@ -1968,7 +1969,7 @@ transform: translateY(-.2rem);
/*================================================= /*=================================================
6.7 Gallery - <ul class="flexblock gallery"> 6.7 Gallery - <ul class="flexblock gallery">
Block Thumbnails li+.overlay+image Block Thumbnails li+.overlay+image
img size recommended:800x600px img size recommended:800x600px
=================================================== */ =================================================== */
@@ -2011,7 +2012,7 @@ img size recommended:800x600px
transition: .1s; transition: .1s;
} }
.gallery li:hover figcaption:before { .gallery li:hover figcaption:before {
top:.3rem; top:.3rem;
} }
.aligncenter .gallery li figcaption:before { .aligncenter .gallery li figcaption:before {
margin-left: 0; margin-left: 0;
@@ -2019,9 +2020,9 @@ top:.3rem;
} }
.gallery li footer { .gallery li footer {
position: relative; position: relative;
padding:1.2rem 0 0; padding:1.2rem 0 0;
margin-top: .8rem; margin-top: .8rem;
} }
@media (min-width:600px) { @media (min-width:600px) {
.flexblock.gallery { .flexblock.gallery {
@@ -2072,16 +2073,16 @@ margin-top: .8rem;
justify-content: center; justify-content: center;
transition: all 0.3s linear; transition: all 0.3s linear;
} }
li .overlay { li .overlay {
align-items: center; align-items: center;
} }
li .overlay h2 { li .overlay h2 {
text-transform: uppercase; text-transform: uppercase;
margin: 0; margin: 0;
padding: 0 2.4rem; padding: 0 2.4rem;
letter-spacing: .2rem; letter-spacing: .2rem;
width: 100%; width: 100%;
text-align: center; text-align: center;
} }
.overlay p, .overlay p,
@@ -2181,7 +2182,7 @@ li:hover .overlay {
/*=========================================== /*===========================================
6.9 Block Activity <ul class="activity"> 6.9 Block Activity <ul class="activity">
CV / News CV / News
============================================= */ ============================================= */
.flexblock.activity { .flexblock.activity {
@@ -2593,7 +2594,7 @@ p + .work {
} }
/*== Images inside container: /*== Images inside container:
object-fit to re-frame images rather than just stretch and resize them === */ object-fit to re-frame images rather than just stretch and resize them === */
@media (min-width: 768px) { @media (min-width: 768px) {
@@ -2896,7 +2897,7 @@ select {
padding: .7rem; padding: .7rem;
font-weight: 400; font-weight: 400;
font-size: 1.6rem; font-size: 1.6rem;
} }
input[type="radio"], input[type="radio"],
input[type="checkbox"] { input[type="checkbox"] {
@@ -2932,7 +2933,7 @@ button {
} }
.button.radius, button.radius,input.radius {border-radius: 2.4rem;} .button.radius, button.radius,input.radius {border-radius: 2.4rem;}
button, button,
input[type="submit"] { input[type="submit"] {
text-transform: uppercase; text-transform: uppercase;
@@ -2991,11 +2992,11 @@ select:focus {
} }
@media (min-width:1024px) { @media (min-width:1024px) {
[class*="badge-"] { [class*="badge-"] {
width: 162px; width: 162px;
height: 48px; height: 48px;
line-height: 4.8rem; line-height: 4.8rem;
} }
} }
.badge-ios { .badge-ios {
background-image: url("../images/bt-appstore.png"); background-image: url("../images/bt-appstore.png");
@@ -3011,8 +3012,8 @@ select:focus {
a.button:hover, a.button:hover,
button[type="submit"]:hover, button[type="submit"]:hover,
input[type="submit"]:hover { input[type="submit"]:hover {
-webkit-transform:scale(1.01); -webkit-transform:scale(1.01);
transform: scale(1.01); transform: scale(1.01);
} }
[class*="badge-"]:hover { [class*="badge-"]:hover {
opacity: 0.7; opacity: 0.7;
@@ -3048,14 +3049,14 @@ transform: scale(1.01);
cursor: pointer; cursor: pointer;
} }
[class*="button"] + [class*="button"],[class*="badge"] + [class*="badge"] { [class*="button"] + [class*="button"],[class*="badge"] + [class*="badge"] {
margin-left: 1.8rem; margin-left: 1.8rem;
} }
} }
@media (max-width:499px) { @media (max-width:499px) {
[class*="button"] + [class*="button"],[class*="badge"] + [class*="badge"] { [class*="button"] + [class*="button"],[class*="badge"] + [class*="badge"] {
margin-top: .8rem; margin-top: .8rem;
} }
} }

View File

@@ -81,27 +81,27 @@ hr:after {
color: #333; color: #333;
} }
bbbr, abbr,
acronym { acronym {
border-bottom: 1px dotted #333; border-bottom: 1px dotted #333;
} }
mark, mark,
ins { ins {
background-color: rgba(221,238,255, 0.8); background-color: rgba(221,238,255, 0.8);
color: inherit; color: inherit;
} }
::-moz-selection { ::-moz-selection {
background-color: rgba(221,238,255, 0.8); background-color: rgba(221,238,255, 0.8);
} }
::-webkit-selection { ::-webkit-selection {
background-color: rgba(221,238,255, 0.8); background-color: rgba(221,238,255, 0.8);
} }
::selection { ::selection {
background-color: rgba(221,238,255, 0.8); background-color: rgba(221,238,255, 0.8);
} }
pre { pre {
@@ -119,7 +119,7 @@ code,[class*="bg-"] pre {
} }
.bg-white code{ .bg-white code{
background: rgba(0, 20, 80, 0.03); background: rgba(0, 20, 80, 0.03);
} }
/*================================================ /*================================================
Slides - Backgrounds <section class="bg-primary"> Slides - Backgrounds <section class="bg-primary">
@@ -218,7 +218,7 @@ Slides - Backgrounds <section class="bg-primary">
/*Covers/Longforms...*/ /*Covers/Longforms...*/
.bg-trans-gradient{ .bg-trans-gradient{
background: linear-gradient(to top, rgba(0,0,0,0.8) 0%,rgba(0,0,0,0) 100%); background: linear-gradient(to top, rgba(0,0,0,0.8) 0%,rgba(0,0,0,0) 100%);
} }
/*Horizontal Gradient*/ /*Horizontal Gradient*/
@@ -250,9 +250,9 @@ background: linear-gradient(to top, rgba(0,0,0,0.8) 0%,rgba(0,0,0,0) 100%);
/*Gray Gradient (horizontal)*/ /*Gray Gradient (horizontal)*/
.bg-gradient-gray{ .bg-gradient-gray{
background: linear-gradient(90deg,#f7f9fb 0,#dee2e6 100%); background: linear-gradient(90deg,#f7f9fb 0,#dee2e6 100%);
color: #333; color: #333;
text-shadow: none; text-shadow: none;
} }
/*Border/Frame*/ /*Border/Frame*/
.frame { .frame {
@@ -261,7 +261,7 @@ text-shadow: none;
/*Layer/Box Shadow*/ /*Layer/Box Shadow*/
.shadow,.pre { .shadow,.pre {
position: relative; position: relative;
} }
.shadow:before,.shadow:after { .shadow:before,.shadow:after {
box-shadow: 0 16px 24px rgba(0, 20, 80, 0.3); box-shadow: 0 16px 24px rgba(0, 20, 80, 0.3);
@@ -274,13 +274,13 @@ TYPOGRAPHY
/* -- Horizontal separator -- */ /* -- Horizontal separator -- */
.text-separator:before { .text-separator:before {
background-color: rgba(170, 0, 0, 0.8); background-color: rgba(170, 0, 0, 0.8);
} }
/* -- Pull Quote (Right/Left) -- */ /* -- Pull Quote (Right/Left) -- */
[class*="text-pull-"] { [class*="text-pull-"] {
border-top: 4px solid rgba(0, 0, 0, 0.5); border-top: 4px solid rgba(0, 0, 0, 0.5);
} }
/* -- Context -- */ /* -- Context -- */
@@ -374,7 +374,7 @@ nav li.email a:hover {
} }
/*========================================= /*=========================================
Features & Clients List Features & Clients List
=========================================== */ =========================================== */
.features li,.clients li { .features li,.clients li {
@@ -387,7 +387,7 @@ Features & Clients List
} }
.features li:hover,.clients li:hover { .features li:hover,.clients li:hover {
box-shadow: 0 8px 16px rgba(0,20,80,.02),0 4px 16px rgba(0,0,0,.08); box-shadow: 0 8px 16px rgba(0,20,80,.02),0 4px 16px rgba(0,0,0,.08);
} }
/*.features li span,.features li svg{color: #44d;}*/ /*.features li span,.features li svg{color: #44d;}*/
@@ -410,7 +410,7 @@ box-shadow: 0 8px 16px rgba(0,20,80,.02),0 4px 16px rgba(0,0,0,.08);
} }
/*=========================================== /*===========================================
flexblock.steps flexblock.steps
============================================= */ ============================================= */
.steps li:nth-child(1) { .steps li:nth-child(1) {
@@ -519,7 +519,7 @@ Gallery li+.overlay+image
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 4px 8px rgba(0, 0, 0, 0.08); box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 4px 8px rgba(0, 0, 0, 0.08);
} }
.gallery li footer { .gallery li footer {
border-top:1px solid rgba(0,20,80,0.1); border-top:1px solid rgba(0,20,80,0.1);
} }
.gallery li a { .gallery li a {
@@ -684,7 +684,7 @@ Cards
/*== Figure Background === */ /*== Figure Background === */
[class*="card-"][class*="bg-"] figure { [class*="card-"][class*="bg-"] figure {
background-color: rgba(0, 20, 80, 0.06); background-color: rgba(0, 20, 80, 0.06);
} }
/*== Ficaption Cards === */ /*== Ficaption Cards === */
@@ -703,7 +703,7 @@ background-color: rgba(0, 20, 80, 0.06);
border-image: linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.4) 50%, transparent) 1 100%; border-image: linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.4) 50%, transparent) 1 100%;
-webkit-border-image: -webkit-linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.4) 50%, transparent) 1 100%; -webkit-border-image: -webkit-linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.4) 50%, transparent) 1 100%;
-moz-border-image: -moz-linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.4) 50%, transparent) 1 100%; -moz-border-image: -moz-linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.4) 50%, transparent) 1 100%;
} }
} }
@@ -737,7 +737,7 @@ tr:nth-child(even)>td:hover {
/*============================ /*============================
Browser (Screenshots) Browser (Screenshots)
============================== */ ============================== */
.browser { .browser {
@@ -783,10 +783,10 @@ input:focus::-moz-placeholder {
input:focus::-webkit-input-placeholder { input:focus::-webkit-input-placeholder {
color: #ddd; color: #ddd;
} }
a.button,[class*="badge-"] a.button,[class*="badge-"],
button[type="submit"], button[type="submit"],
input { input {
box-shadow: 0px 10px 16px -8px rgba(0, 20, 80, 0.3); box-shadow: 0 10px 16px -8px rgba(0, 20, 80, 0.3);
} }
button, button,
@@ -797,7 +797,7 @@ button[type="submit"],
input[type="submit"], input[type="submit"],
.button,.button:hover, .button,.button:hover,
button[type="submit"]:hover, button[type="submit"]:hover,
input[type="submit"]:hover input[type="submit"]:hover
{ {
border: 1px solid #44d; border: 1px solid #44d;
} }
@@ -810,7 +810,7 @@ input[type="submit"],
text-shadow: 0 1px 0 #123; text-shadow: 0 1px 0 #123;
} }
.button:active,button[type="submit"]:active,input[type="submit"]:active { .button:active,button[type="submit"]:active,input[type="submit"]:active {
background-color: #17d; background-color: #17d;
} }
.ghost,.ghost:hover {background: none;color: inherit;text-shadow: none;} .ghost,.ghost:hover {background: none;color: inherit;text-shadow: none;}
.bg-primary select, .bg-primary select,
@@ -818,7 +818,7 @@ background-color: #17d;
.bg-primary .button, .bg-primary .button,
.bg-primary button,.bg-primary button:hover, .bg-primary button,.bg-primary button:hover,
.bg-primary input, .bg-primary input,
[class*="bg-gradient-"] .button,[class*="bg-"] a.button.ghost [class*="bg-gradient-"] .button,[class*="bg-"] a.button.ghost
{ {
border-color: #fff; border-color: #fff;
} }

View File

@@ -1,515 +0,0 @@
/*==================================================================
Name: WebSlides
Version: 0.1.1 (trackpad gestures and keyboard shortcuts).
Date: 2017-02-11
Description: HTML presentations made easy.
URL: https://github.com/jlantunez/WebSlides
Thanks @LuisSacristan for your help :)
-
Based on SimpleSlides, by Jenn Schiffer:
https://github.com/jennschiffer/SimpleSlides
==================================================================== */
jQuery.fn.webslides = function(options) {
var obj = {};
var $this = jQuery(this);
// Private vars
var easing = 'swing';
var slideOffset = 50; // minimun number of pixels for sliding
var verticalDelay = 150; // to avoid 2 slides in a row
var wheelDetail = -3; // how far the wheel turned for Firefox
var wheelDelta = 150; // how far the wheel turned for Chrome
var isMobile = ('ontouchstart' in document.documentElement && navigator.userAgent.match(/Mobi/));
var $slideshow,
$navigation,
$slides,
$counter,
$next,
$previous,
$currentSlide,
$firstSlide,
$lastSlide,
$auxSlide = null,
slidePointer,
intervalId;
var total = 0;
var labels = {};
/**
* Init function
* @param {Object} settings Plugin settings
* @param {string} id Container HTML ID
* @param {string} class Slide class
* @param {string} counter Counter container ID
* @param {string} navigation Navigation container ID
* @param {string} next Next HTML element ID
* @param {string} previous Previous HTML element ID
* @param {string} current Current HTML element ID
* @param {string} verticalClass Vertical class
* @param {boolean} autoslide Auto slide, default false
*/
var init = function(_options) {
obj.settings = {
class : 'slide',
counter : 'counter',
navigation : 'navigation',
next : 'next',
previous : 'previous',
current : 'current',
verticalClass : 'vertical', // #webslides.vertical - You must add this class to slideshow for vertical sliding
interval : false,
};
// Allow overriding the default config
$.extend( obj.settings, _options );
setup();
run();
initClickEvents();
initKeyEvents();
initMouseWheel();
initTouchEvents();
initHash();
}
var setup = function() {
$slideshow = $this;
$navigation = jQuery('<div>').attr('id', obj.settings.navigation);
$slides = $slideshow.children('section').addClass(obj.settings.class);
$firstSlide = $slides.first();
$lastSlide = $slides.last();
total = $slides.length;
labels = {
next : $slideshow.hasClass(obj.settings.verticalClass)?'&darr;':'&rarr;',
previous : $slideshow.hasClass(obj.settings.verticalClass)?'&uarr;':'&larr;',
separator : ' / '
};
// make sure the last slide doesn't page break while printing.
jQuery('head').append( '<style> .slide:nth-child(' + total + ') { page-break-after: auto }</style>' );
// remove non-section children (like html comments which wp wraps in <p> tags)
$slideshow.children().not('section').remove();
// add navigational arrows and counter
$navigation.append(jQuery('<a href="#" title="Arrow Keys">').attr('id',obj.settings.previous).html(labels.previous));
$navigation.append(jQuery('<a href="#" title="Arrow Keys">').attr('id',obj.settings.next).html(labels.next));
$slideshow.append($navigation);
$slideshow.append(jQuery('<span>').attr('id',obj.settings.counter));
$counter = jQuery('#'+obj.settings.counter),
$next = jQuery('#'+obj.settings.next),
$previous = jQuery('#'+obj.settings.previous);
$navigation.append($counter);
$slideshow.data('moving', false);
};
/**
* Starts sliders
*/
var run = function() {
// Initially hide all slides
$slides.hide();
// The first slide is number first, last is slides length
slidePointer = {
current : 1,
last : $slides.length
};
var slideState = parseInt(document.location.hash.replace('#slide=', ''));
if ( slideState && (slideState > 0 && slideState <= $slides.length )) {
// if slide= hash state is given and valid, go to that slide
obj.goToSlide(slideState);
}
else {
// The first slide is the first slide, so make visible and set the counter...
$currentSlide = $firstSlide.show().addClass(obj.settings.current);
updateCounter();
}
obj.autoslide();
};
/**
* Init click events
*/
var initClickEvents = function() {
// "next" arrow clicked => next slide
$next.click( function(e){
e.preventDefault();
obj.nextSlide();
});
// "previous" arrow clicked => previous slide
$previous.click( function(e){
e.preventDefault();
obj.previousSlide();
});
}
/**
* Init keypress events
*/
var initKeyEvents = function() {
// Add keyboard shortcuts for changing slides
jQuery(document).keydown(function(e){
if (!$slideshow.hasClass(obj.settings.verticalClass) || isMobile) {
$slideshow.data('iswheel', false);
if (e.which == 39 || e.which == 32) {
// right key pressed => next slide
obj.nextSlide();
return false;
}
else if (e.which == 37) {
// left or l key pressed => previous slide
obj.previousSlide();
return false;
}
}
});
// Add keyboard shortcuts for changing slides
jQuery(document).keydown(function(e){
if ($slideshow.hasClass(obj.settings.verticalClass) && !isMobile) {
$slideshow.data('iswheel', false);
if (e.which == 40 || e.which == 32) {
// right key pressed => next slide
obj.nextSlide();
return false;
}
else if (e.which == 38) {
// left or l key pressed => previous slide
obj.previousSlide();
return false;
}
}
});
}
/**
* Init mouse wheel
*/
var initMouseWheel = function() {
// Mouse wheel
jQuery(window).bind('mousewheel DOMMouseScroll', function(event){
$slideshow.data('iswheel', true);
if ($slideshow.hasClass(obj.settings.verticalClass) && !isMobile) {
if (event.originalEvent.wheelDelta > wheelDelta || event.originalEvent.detail <= wheelDetail) {
// Scroll up
obj.previousSlide();
} else if (event.originalEvent.wheelDelta < -wheelDelta || event.originalEvent.detail >= -wheelDetail) {
// scroll down
obj.nextSlide();
}
}
});
}
/**
* Init touch events
*/
var initTouchEvents = function() {
// Touch
jQuery(window).on("touchstart", function(ev) {
var e = ev.originalEvent;
$slideshow.data('touchYStart', e.touches[0].screenY);
$slideshow.data('touchXStart', e.touches[0].screenX);
$slideshow.data('touchYEnd', e.touches[0].screenY);
$slideshow.data('touchXEnd', e.touches[0].screenX);
});
jQuery(window).on("touchmove", function(ev) {
var e = ev.originalEvent;
$slideshow.data('touchYEnd', e.touches[0].screenY);
$slideshow.data('touchXEnd', e.touches[0].screenX);
});
jQuery(window).on("touchend", function(ev) {
$slideshow.data('iswheel', false);
var e = ev.originalEvent;
var diffX = $slideshow.data('touchXStart') - $slideshow.data('touchXEnd');
var diffY = $slideshow.data('touchYStart') - $slideshow.data('touchYEnd');
if ((!$slideshow.hasClass(obj.settings.verticalClass) || isMobile) && Math.abs(diffX) > Math.abs(diffY)) {
if(diffX < -slideOffset) {
obj.previousSlide();
// Scroll up
} else if(diffX > slideOffset) {
// scroll down
obj.nextSlide();
}
}
});
}
/**
* Autoslide process
*/
obj.autoslide = function() {
if (obj.settings.interval != false && obj.settings.interval > 0) {
clearInterval(intervalId);
intervalId = setInterval(obj.nextSlide, obj.settings.interval);
}
}
/**
* Init hash
*/
var initHash = function() {
/**
* Bind the event HashChange when the prev/next history button was clicked
*/
jQuery(window).bind("hashchange", function () {
if (hasHash()) {
goToSlideIfSlideHashChange();
} else {
window.location.reload();
}
});
function hasHash() {
return window.location.hash ? true : false;
}
function goToSlideIfSlideHashChange() {
var paramsArr = getArrayOfHashParams();
var slideObj = $.grep(paramsArr, function (e) {
return (e.key == "slide");
});
if (slideObj.length == 1) {
obj.goToSlide(slideObj[0].value);
}
}
function getArrayOfHashParams() {
var hash = window.location.hash.replace('#', '').split('&');
var paramsArr = new Array([]);
for (var i = 0; i < hash.length; i++) {
var itemArray = hash[i].split('=');
var action = new Object({});
action.key = itemArray[0];
action.value = itemArray[1];
paramsArr.push(action);
}
return paramsArr;
}
}
/*** FUNCTIONS ***/
/**
* Updates slider counter
*/
var updateCounter = function() {
// updates the counter
$counter.text(slidePointer.current + labels.separator + slidePointer.last);
};
/**
* Updates current URL with counter position
*/
var updateURL = function() {
// updates slide state
var currentURL = document.location.toString();
if (currentURL.indexOf('#') != 1){
currentURL = currentURL.substr(0,currentURL.indexOf('#'));
}
history.pushState(null, null, '#slide='+ slidePointer.current );
};
/**
* Hides current Slide
*/
var hideCurrentSlide = function() {
// hide the current slide
if ( $currentSlide ) {
$currentSlide.hide().removeClass(obj.settings.current);
}
};
/**
* Goes to next slide
*/
obj.nextSlide = function() {
var nextSlide;
if ($slideshow.hasClass(obj.settings.verticalClass) && !isMobile) { // Is vertical
if ($slideshow.data('moving')) return;
$slideshow.data('moving', true);
jQuery('html').css({overflow: 'hidden'});
nextSlide = $currentSlide.next();
slidePointer.current = ((slidePointer.current+1)%total);
if (slidePointer.current === 0) slidePointer.current = total;
// show next slide
nextSlide.show().addClass(obj.settings.current);
// scroll to next slide
var animated = false;
jQuery('html, body').animate({scrollTop: nextSlide.offset().top}, 500, easing, function() {
if (!animated) {
$currentSlide.hide().removeClass(obj.settings.current);
$currentSlide.siblings('.slide').last().after($currentSlide);
$currentSlide = nextSlide;
// update counter
updateCounter();
// update url
updateURL();
// fire slide event
fireSlideEvent();
jQuery('html').css({overflow: 'auto'});
setTimeout(function() {$slideshow.data('moving', false);}, $slideshow.data('iswheel')?verticalDelay:0);
}
animated = true;
});
} else { // Is landscape
jQuery("html, body").animate({ scrollTop: 0 }, 0);
// hide current slide
hideCurrentSlide();
// get the next slide
nextSlide = $currentSlide.next();
nextSlide.show().addClass(obj.settings.current);
$currentSlide.siblings('.slide').last().after($currentSlide);
$currentSlide = nextSlide;
slidePointer.current = ((slidePointer.current+1)%total);
if (slidePointer.current == 0) slidePointer.current = total;
// update counter
updateCounter();
// update url
updateURL();
// fire slide event
fireSlideEvent();
}
obj.autoslide();
};
/**
* Goes to previous slide
*/
obj.previousSlide = function() {
var prevSlide;
if ($slideshow.hasClass(obj.settings.verticalClass) && !isMobile) { // Is vertical
if ($slideshow.data('moving')) return;
$slideshow.data('moving', true);
jQuery('html').css({overflow: 'hidden'});
$currentSlide.before($currentSlide.siblings('.slide').last());
prevSlide = $currentSlide.prev();
if (prevSlide.length === 0) return false;
// show next slide
prevSlide.show().addClass(obj.settings.current);
// scroll to next slide
var animated = false;
jQuery('html, body').scrollTop($currentSlide.offset().top);
jQuery('html, body').animate({scrollTop: prevSlide.offset().top}, 500, easing, function() {
if (!animated) {
$currentSlide.hide().removeClass(obj.settings.current);
$currentSlide = prevSlide;
// not the last slide => go to the next one and increment the counter
$currentSlide = prevSlide;
slidePointer.current = slidePointer.current== 1? total : (slidePointer.current-1);
// update counter
updateCounter();
// update url
updateURL();
// fire slide event
fireSlideEvent();
jQuery('html').css({overflow: 'auto'});
setTimeout(function() {$slideshow.data('moving', false);}, $slideshow.data('iswheel')?verticalDelay:0);
}
animated = true;
});
} else { // Is landscape
jQuery("html, body").animate({ scrollTop: 0 }, 0);
// hide current slide
hideCurrentSlide();
// get the previous slide
$currentSlide.before($currentSlide.siblings('.slide').last());
prevSlide = $currentSlide.prev();
prevSlide.show().addClass(obj.settings.current);
$currentSlide = prevSlide;
slidePointer.current = slidePointer.current== 1? total : (slidePointer.current-1);
// update counter
updateCounter();
// update URL
updateURL();
// fire slide event
fireSlideEvent();
}
obj.autoslide();
};
/**
* Goes to a specific slide
*
* @param {number} slideNumber Where to go
*/
obj.goToSlide = function(slideNumber) {
// hide current slide
hideCurrentSlide();
moveToSlide = slideNumber-1;
$currentSlide = $slides.eq(moveToSlide);
$currentSlide.show().addClass(obj.settings.current);
jQuery('.slide:lt('+$currentSlide.index()+')').each(function() {
var $this = jQuery(this);
$this.siblings('.slide').last().after($this);
});
slidePointer.current = slideNumber;
// update counter
updateCounter();
obj.autoslide();
};
/**
* Fires slide event
*/
var fireSlideEvent = function(slide) {
var slideEvent = new window.CustomEvent('slidechanged', {
detail: { slide: slide || $currentSlide }
});
window.dispatchEvent(slideEvent);
};
// Init plugin
init(options);
// Return same object
return obj;
}

27
webpack.config.babel.js Normal file
View File

@@ -0,0 +1,27 @@
const path = require('path');
const src = path.join(__dirname, 'src');
module.exports = {
context: src,
entry: {
webslides: './js/full.js'
},
output: {
filename: '[name].js',
path: path.join(__dirname, 'static/js'),
publicPath: '/static/js/'
},
devServer: {
contentBase: __dirname,
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
include: src
}
]
}
};