mirror of
https://github.com/webslides/WebSlides.git
synced 2025-08-16 10:04:45 +02:00
Merge pull request #41 from Belelros/master
WebSlides 1.0 - Architecture change
This commit is contained in:
20
.editorconfig
Normal file
20
.editorconfig
Normal 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
18
.gitignore
vendored
Normal 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*
|
49
CHANGELOG.md
49
CHANGELOG.md
@@ -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.
|
||||
- .tabs removed.
|
||||
- webslides-lite.js removed.
|
||||
- `.tabs` removed.
|
||||
- `webslides-lite.js` removed.
|
||||
|
||||
## 0.1 (2017-01-08)
|
||||
# 0.1.0 (2017-01-08)
|
||||
|
||||
- Initial release.
|
||||
|
84
README.md
84
README.md
@@ -1,7 +1,11 @@
|
||||
# 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.
|
||||
[](http://opensource.org/licenses/MIT)
|
||||
[](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?
|
||||
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.
|
||||
- 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.
|
||||
- Each parent <code><section></code> in the #webslides element is an individual slide.
|
||||
- Each parent `<section>` in the `#webslides` element is an individual slide.
|
||||
|
||||
<pre><article id="webslides">
|
||||
<section>
|
||||
<h1>Slide 1</h1>
|
||||
</section>
|
||||
<section class="bg-black aligncenter">
|
||||
<span class="code-comment"><!-- .wrap = container 1200px --></span>
|
||||
<div class="wrap">
|
||||
<h1>Slide 2</h1>
|
||||
</div>
|
||||
</section>
|
||||
</article></pre>
|
||||
|
||||
#### Vertical Sliding
|
||||
|
||||
<pre><article id="webslides" class="vertical"></pre>
|
||||
|
||||
### How it works
|
||||
|
||||
You need to add the follow javascript to initialize the webslides object.
|
||||
|
||||
```javascript
|
||||
var slide = jQuery('#webslides').webslides();
|
||||
```html
|
||||
<article id="webslides">
|
||||
<section>
|
||||
<h1>Slide 1</h1>
|
||||
</section>
|
||||
<section class="bg-black aligncenter">
|
||||
<!-- .wrap = container 1200px -->
|
||||
<div class="wrap">
|
||||
<h1>Slide 2</h1>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
```
|
||||
|
||||
#### Auto slide
|
||||
### Vertical Sliding
|
||||
|
||||
```javascript
|
||||
var slide = jQuery('#webslides').webslides({interval: 5000});
|
||||
```
|
||||
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);
|
||||
```html
|
||||
<article id="webslides" class="vertical">
|
||||
```
|
||||
|
||||
### 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.
|
||||
|
||||
```
|
||||
@@ -84,16 +68,17 @@ webslides/
|
||||
|
||||
### CSS Syntax (classes)
|
||||
|
||||
- Typography: .text-landing, .text-data, .text-intro...
|
||||
- Background Colors: .bg-primary, .bg-apple, .bg-blue...
|
||||
- Background Images: .background,.background-center-bottom...
|
||||
- Cards: .card-50, .card-40...
|
||||
- Flexible Blocks: .flexblock.clients, .flexblock.metrics...
|
||||
- Typography: `.text-landing`, `.text-data`, `.text-intro`...
|
||||
- Background Colors: `.bg-primary`, `.bg-apple`, `.bg-blue`...
|
||||
- Background Images: `.background`,`.background-center-bottom`...
|
||||
- Cards: `.card-50`, `.card-40`...
|
||||
- Flexible Blocks: `.flexblock.clients`, `.flexblock.metrics`...
|
||||
|
||||
|
||||
### Extensions
|
||||
|
||||
You can add:
|
||||
|
||||
- [Unsplash](https://unsplash.com) photos
|
||||
- [animate.css](https://daneden.github.io/animate.css)
|
||||
- [particles.js](https://github.com/VincentGarreau/particles.js)
|
||||
@@ -101,9 +86,16 @@ You can add:
|
||||
|
||||
### 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.
|
||||
|
||||
### 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
|
||||
|
||||
- WebSlides was created by [@jlantunez](https://twitter.com/jlantunez) using [Cactus](https://github.com/eudicots/Cactus).
|
||||
|
@@ -1933,16 +1933,13 @@
|
||||
</main>
|
||||
<!--main-->
|
||||
|
||||
<!-- jQuery (required for slides to work) -->
|
||||
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
|
||||
<script src="../static/js/svg-icons.js"></script>
|
||||
<script src="../static/js/webslides.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var slide = jQuery('#webslides').webslides();
|
||||
<script>
|
||||
window.ws = new WebSlides();
|
||||
</script>
|
||||
|
||||
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
|
||||
<script defer src="../static/js/svg-icons.js"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -319,7 +319,11 @@
|
||||
<section>
|
||||
<div class="wrap">
|
||||
<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">
|
||||
<ul>
|
||||
<li><a href="">About</a></li>
|
||||
@@ -368,8 +372,9 @@
|
||||
</ul>
|
||||
</nav>
|
||||
<p>nav.navbar</p>
|
||||
|
||||
<hr>
|
||||
</div>
|
||||
<!-- end .tab-content -->
|
||||
<div id="tab-2" class="tab-content">
|
||||
<div class="grid">
|
||||
<div class="column">
|
||||
<h3>Company</h3>
|
||||
@@ -430,6 +435,8 @@
|
||||
<!-- .end .column -->
|
||||
</div>
|
||||
<!-- .end .grid -->
|
||||
</div>
|
||||
<!-- end .tab-content -->
|
||||
</div>
|
||||
<!-- .end .wrap -->
|
||||
</section>
|
||||
@@ -1796,8 +1803,49 @@
|
||||
<section class="aligncenter">
|
||||
<!--.wrap = container 1200px -->
|
||||
<div class="wrap">
|
||||
<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 id="tab-3" class="tab-content current">
|
||||
<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>
|
||||
</section>
|
||||
<section class="bg-black aligncenter">
|
||||
@@ -3078,16 +3126,14 @@
|
||||
</main>
|
||||
<!--main-->
|
||||
|
||||
<!-- jQuery (required for slides to work) -->
|
||||
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
|
||||
<script src="../static/js/svg-icons.js"></script>
|
||||
<script src="../static/js/webslides.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var slide = jQuery('#webslides').webslides();
|
||||
<script>
|
||||
window.ws = new WebSlides();
|
||||
</script>
|
||||
|
||||
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
|
||||
<script defer src="../static/js/svg-icons.js"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -92,7 +92,7 @@
|
||||
</header>
|
||||
|
||||
<main role="main">
|
||||
<article id="webslides" class="vertical">
|
||||
<article> <!-- Slideshow? id="webslides" -->
|
||||
|
||||
<!-- Quick Guide
|
||||
- Each parent <section> in the <article id="webslides"> element is an individual slide.
|
||||
@@ -107,7 +107,7 @@
|
||||
<h1><strong>WebSlides Demos</strong></h1>
|
||||
<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>
|
||||
<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&src=typd" title="#WebSlides on Twitter">#WebSlides</a>.</p>
|
||||
</div>
|
||||
<!-- .end .wrap -->
|
||||
</section>
|
||||
@@ -222,16 +222,14 @@
|
||||
</main>
|
||||
<!-- end main -->
|
||||
|
||||
<!-- jQuery (required for slides to work) -->
|
||||
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
|
||||
<script src="../static/js/svg-icons.js"></script>
|
||||
<script src="../static/js/webslides.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var slide = jQuery('#webslides').webslides();
|
||||
<script>
|
||||
window.ws = new WebSlides();
|
||||
</script>
|
||||
|
||||
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
|
||||
<script defer src="../static/js/svg-icons.js"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -843,16 +843,14 @@
|
||||
</main>
|
||||
<!--main-->
|
||||
|
||||
<!-- jQuery (required for slides to work) -->
|
||||
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
|
||||
<script src="../static/js/svg-icons.js"></script>
|
||||
<script src="../static/js/webslides.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var slide = jQuery('#webslides').webslides();
|
||||
<script>
|
||||
window.ws = new WebSlides();
|
||||
</script>
|
||||
|
||||
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
|
||||
<script defer src="../static/js/svg-icons.js"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -1918,16 +1918,13 @@
|
||||
</main>
|
||||
<!--main-->
|
||||
|
||||
<!-- jQuery (required for slides to work) -->
|
||||
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
|
||||
<script src="../static/js/svg-icons.js"></script>
|
||||
<script src="../static/js/webslides.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var slide = jQuery('#webslides').webslides();
|
||||
<script>
|
||||
window.ws = new WebSlides();
|
||||
</script>
|
||||
|
||||
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
|
||||
<script defer src="../static/js/svg-icons.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -1858,16 +1858,14 @@
|
||||
</main>
|
||||
<!--main-->
|
||||
|
||||
<!-- jQuery (required for slides to work) -->
|
||||
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
|
||||
<script src="../static/js/svg-icons.js"></script>
|
||||
<script src="../static/js/webslides.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var slide = jQuery('#webslides').webslides();
|
||||
<script>
|
||||
window.ws = new WebSlides();
|
||||
</script>
|
||||
|
||||
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
|
||||
<script defer src="../static/js/svg-icons.js"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -66,7 +66,6 @@
|
||||
<!-- Android -->
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="theme-color" content="#333333">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<header role="banner">
|
||||
@@ -339,13 +338,11 @@
|
||||
</main>
|
||||
<!--main-->
|
||||
|
||||
<!-- jQuery (required for slides to work) -->
|
||||
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
|
||||
<script src="../static/js/svg-icons.js"></script>
|
||||
<script src="../static/js/webslides.js"></script>
|
||||
|
||||
<!-- Autoslide 5 seconds. If you don't want autoslide, remove: {interval: 5000} -->
|
||||
<script type="text/javascript">
|
||||
var slide = jQuery('#webslides').webslides({interval: 5000});
|
||||
<!-- Autoslide 5 seconds. If you don't want autoslide, remove: {autoslide: 5000} -->
|
||||
<script>
|
||||
window.ws = new WebSlides({ autoslide: 5000 });
|
||||
</script>
|
||||
|
||||
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
|
||||
|
135
docs/technical.md
Normal file
135
docs/technical.md
Normal 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
|
12
index.html
12
index.html
@@ -94,7 +94,6 @@
|
||||
|
||||
<main role="main">
|
||||
<article id="webslides" class="vertical">
|
||||
|
||||
<!-- Quick Guide
|
||||
- Each parent <section> in the <article id="webslides"> element is an individual slide.
|
||||
- Vertical sliding = <article id="webslides" class="vertical">
|
||||
@@ -384,17 +383,14 @@
|
||||
</div>
|
||||
</footer> -->
|
||||
|
||||
<!-- jQuery (required for slides to work) -->
|
||||
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
|
||||
<script src="static/js/svg-icons.js"></script>
|
||||
<script src="static/js/webslides.js"></script>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var slide = jQuery('#webslides').webslides();
|
||||
<script>
|
||||
window.ws = new WebSlides();
|
||||
</script>
|
||||
|
||||
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
|
||||
<script defer src="static/js/svg-icons.js"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
48
package.json
Normal file
48
package.json
Normal 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
3
src/js/full.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import WebSlides from './modules/webslides';
|
||||
|
||||
window.WebSlides = WebSlides;
|
82
src/js/modules/slide.js
Normal file
82
src/js/modules/slide.js
Normal 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
364
src/js/modules/webslides.js
Normal 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
44
src/js/plugins/grid.js
Normal 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
71
src/js/plugins/hash.js
Normal 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}`);
|
||||
}
|
||||
}
|
||||
}
|
49
src/js/plugins/keyboard.js
Normal file
49
src/js/plugins/keyboard.js
Normal 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_);
|
||||
}
|
||||
}
|
||||
}
|
120
src/js/plugins/navigation.js
Normal file
120
src/js/plugins/navigation.js
Normal 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
15
src/js/plugins/plugins.js
Normal 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
50
src/js/plugins/scroll.js
Normal 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
151
src/js/plugins/touch.js
Normal 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 };
|
||||
}
|
||||
};
|
38
src/js/utils/custom-event.js
Normal file
38
src/js/utils/custom-event.js
Normal 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
75
src/js/utils/dom.js
Normal 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
19
src/js/utils/easing.js
Normal 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
10
src/js/utils/keys.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const Keys = {
|
||||
ENTER: 13,
|
||||
SPACE: 32,
|
||||
LEFT: 37,
|
||||
UP: 38,
|
||||
RIGHT: 39,
|
||||
DOWN: 40
|
||||
};
|
||||
|
||||
export default Keys;
|
64
src/js/utils/mobile-detector.js
Normal file
64
src/js/utils/mobile-detector.js
Normal 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
74
src/js/utils/scroll-to.js
Normal 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 };
|
@@ -1,9 +1,9 @@
|
||||
/*---------------------------------------------------------------------------------
|
||||
|
||||
App: WebSlides
|
||||
Version: 0.1.1
|
||||
Version: 1.0.0
|
||||
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 URI: http://twitter.com/jlantunez
|
||||
License: The MIT License (MIT)
|
||||
@@ -23,11 +23,11 @@
|
||||
2.3 San Francisco Font (Apple)
|
||||
3. Header & Footer
|
||||
3.1 Logo
|
||||
4. Navigation
|
||||
4. Navigation
|
||||
4.1 Navbars
|
||||
5. SLIDES (vertically and horizontally centered)
|
||||
5.1 Mini container & Alignment
|
||||
5.2 Counter / Navigation Slides
|
||||
5.1 Mini container & Alignment
|
||||
5.2 Counter / Navigation Slides
|
||||
5.3 Background Images/Video
|
||||
6. Magic blocks = .flexblock (Flexible blocks with auto-fill and equal height).
|
||||
6.1 .flexblock.features
|
||||
@@ -56,11 +56,11 @@
|
||||
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 {
|
||||
display: block;
|
||||
}
|
||||
article, aside, details, figcaption, figure, footer, header, main, menu, nav, section, summary {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
@@ -215,7 +215,7 @@ ins {
|
||||
text-decoration: none;
|
||||
padding: 0 4px;
|
||||
text-shadow: none;
|
||||
|
||||
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
@@ -291,7 +291,7 @@ dd {
|
||||
|
||||
|
||||
/*=== 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; }
|
||||
|
||||
/*=========================================
|
||||
@@ -302,7 +302,7 @@ body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* == Prototype faster - Vertical rhythm == */
|
||||
/* == Prototype faster - Vertical rhythm == */
|
||||
|
||||
body.baseline {
|
||||
background: url(../images/baseline.png) left top .8rem/.8rem;
|
||||
@@ -343,7 +343,7 @@ nav a[rel="external"] em,
|
||||
|
||||
/*Layer/Box Shadow*/
|
||||
.shadow {
|
||||
position: relative;
|
||||
position: relative;
|
||||
}
|
||||
.shadow:before,.shadow:after {
|
||||
z-index: -1;
|
||||
@@ -472,8 +472,8 @@ pre code {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*=== 1.2 Animations ================
|
||||
Just 3 basic animations:
|
||||
/*=== 1.2 Animations ================
|
||||
Just 3 basic animations:
|
||||
.fadeIn, .fadeInUp, .zoomIn.
|
||||
https://github.com/daneden/animate.css*/
|
||||
|
||||
@@ -674,9 +674,9 @@ li .browser {margin-bottom: 0;
|
||||
content: "● ● ●";
|
||||
}
|
||||
@media (min-width:768px) {
|
||||
.browser:before {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
.browser:before {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -718,7 +718,7 @@ Auto-fill & Equal height === */
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-transition: .3s;
|
||||
transition: .3s;
|
||||
transition: .3s;
|
||||
padding: 2.4rem;
|
||||
}
|
||||
|
||||
@@ -732,21 +732,21 @@ Auto-fill & Equal height === */
|
||||
}
|
||||
/* Grid (Sidebar + Main) .grid.sm */
|
||||
.grid.sm .column:nth-child(1) {
|
||||
width: 30%
|
||||
width: 30%
|
||||
}
|
||||
.grid.sm .column:nth-child(2) {
|
||||
width: 70%;
|
||||
width: 70%;
|
||||
}
|
||||
/* Grid (Main + Sidebar) .grid.ms */
|
||||
.grid.ms .column:nth-child(1) {
|
||||
width: 70%
|
||||
width: 70%
|
||||
}
|
||||
.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) {
|
||||
width: 50%;
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -807,7 +807,7 @@ ul.description {
|
||||
}
|
||||
|
||||
.description + p{
|
||||
margin-top: 3.2rem;
|
||||
margin-top: 3.2rem;
|
||||
}
|
||||
|
||||
.description li {
|
||||
@@ -818,7 +818,7 @@ margin-top: 3.2rem;
|
||||
transition: .3s;
|
||||
}
|
||||
.description li:hover{
|
||||
padding-left: .4rem;
|
||||
padding-left: .4rem;
|
||||
}
|
||||
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;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
@@ -908,10 +908,10 @@ h1+img,h2+img,h3+img {
|
||||
[class*="content-"] > [class*="content-"] h2,
|
||||
[class*="content-"] > [class*="content-"] h3,
|
||||
[class*="content-"] > [class*="content-"] h4 {
|
||||
font-size: 2.4rem;
|
||||
line-height: 4rem;
|
||||
font-size: 2.4rem;
|
||||
line-height: 4rem;
|
||||
}
|
||||
/*=========================================
|
||||
/*=========================================
|
||||
2.1. Headings with background
|
||||
=========================================== */
|
||||
|
||||
@@ -922,11 +922,11 @@ li[class*="bg-"],p[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 {
|
||||
@@ -948,9 +948,9 @@ padding: .4rem .8rem;
|
||||
@media (min-width: 768px) {
|
||||
.text-landing {
|
||||
letter-spacing: 1.6rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* -- Subtitle (Before h1, h2) --
|
||||
/* -- Subtitle (Before h1, h2) --
|
||||
p.subtitle + h1/h2 */
|
||||
|
||||
p.text-subtitle {
|
||||
@@ -996,7 +996,7 @@ p.text-subtitle svg {vertical-align: text-top;}
|
||||
/* -- Magazine Two Columns -- */
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.text-cols {
|
||||
.text-cols {
|
||||
-webkit-column-count: 2;
|
||||
-moz-column-count: 2;
|
||||
column-count: 2;
|
||||
@@ -1004,10 +1004,10 @@ p.text-subtitle svg {vertical-align: text-top;}
|
||||
-moz-column-gap: 4.8rem;
|
||||
column-gap: 4.8rem;
|
||||
text-align: left;
|
||||
}
|
||||
.text-landing + .text-cols{
|
||||
margin-top: 3.2rem;
|
||||
}
|
||||
}
|
||||
.text-landing + .text-cols{
|
||||
margin-top: 3.2rem;
|
||||
}
|
||||
}
|
||||
.text-cols p:first-child:first-letter {
|
||||
font-size: 11rem;
|
||||
@@ -1037,7 +1037,7 @@ margin-top: 3.2rem;
|
||||
margin-bottom: .6rem;
|
||||
}
|
||||
.column .text-context:before {
|
||||
width:100%;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
/* -- Separator/Symbols (stars ***...) -- */
|
||||
@@ -1047,63 +1047,63 @@ width:100%;
|
||||
|
||||
/* -- Separator -- */
|
||||
.text-separator {
|
||||
margin-top:2.4rem;
|
||||
margin-top:2.4rem;
|
||||
}
|
||||
.text-separator:before {
|
||||
position: absolute;
|
||||
width: 16%;
|
||||
height: .4rem;
|
||||
content: "";
|
||||
margin-top:-1.6rem;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
width: 16%;
|
||||
height: .4rem;
|
||||
content: "";
|
||||
margin-top:-1.6rem;
|
||||
left: 0;
|
||||
}
|
||||
@media (min-width: 568px) {
|
||||
.text-separator {
|
||||
.text-separator {
|
||||
width: 80%;
|
||||
margin-top: 0;
|
||||
margin-left: 20%;
|
||||
}
|
||||
.text-separator:before {
|
||||
}
|
||||
.text-separator:before {
|
||||
margin-top: 1.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -- Pull Quote (Right/Left) -- */
|
||||
|
||||
[class*="text-pull"] {
|
||||
position: relative;
|
||||
font-size: 2.4rem;
|
||||
line-height: 4rem;
|
||||
font-weight: 400;
|
||||
margin-right: 2.4rem;
|
||||
margin-left: 2.4rem;
|
||||
position: relative;
|
||||
font-size: 2.4rem;
|
||||
line-height: 4rem;
|
||||
font-weight: 400;
|
||||
margin-right: 2.4rem;
|
||||
margin-left: 2.4rem;
|
||||
}
|
||||
|
||||
[class*="text-pull-"] {
|
||||
padding-top: 1.4rem;
|
||||
margin-top: .8rem;
|
||||
padding-top: 1.4rem;
|
||||
margin-top: .8rem;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
[class*="text-pull"] {
|
||||
margin-right: -4rem;
|
||||
margin-left: -4rem;
|
||||
}
|
||||
@media (min-width: 1024px) {
|
||||
[class*="text-pull"] {
|
||||
margin-right: -4rem;
|
||||
margin-left: -4rem;
|
||||
}
|
||||
}
|
||||
@media (min-width: 568px) {
|
||||
[class*="text-pull-"] {
|
||||
width: 32rem;
|
||||
}
|
||||
.text-pull-right {
|
||||
float: right;
|
||||
margin-right: -2.4rem;
|
||||
margin-left: 2.4rem;
|
||||
}
|
||||
.text-pull-left {
|
||||
float: left;
|
||||
margin-left: -2.4rem;
|
||||
margin-right: 2.4rem;
|
||||
}
|
||||
@media (min-width: 568px) {
|
||||
[class*="text-pull-"] {
|
||||
width: 32rem;
|
||||
}
|
||||
.text-pull-right {
|
||||
float: right;
|
||||
margin-right: -2.4rem;
|
||||
margin-left: 2.4rem;
|
||||
}
|
||||
.text-pull-left {
|
||||
float: left;
|
||||
margin-left: -2.4rem;
|
||||
margin-right: 2.4rem;
|
||||
}
|
||||
}
|
||||
/* -- 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 {
|
||||
@@ -1169,8 +1169,8 @@ footer,
|
||||
|
||||
header p,
|
||||
footer p {
|
||||
line-height: 4.8rem;
|
||||
margin-bottom: 0;
|
||||
line-height: 4.8rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
header[role=banner] img,
|
||||
@@ -1197,7 +1197,7 @@ section footer {
|
||||
|
||||
/*desktop only? Add @media (min-width: 1025px)*/
|
||||
header[role=banner] {
|
||||
opacity: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
/*=== Show Header[role=banner] === */
|
||||
header[role=banner]:hover {
|
||||
@@ -1205,10 +1205,10 @@ header[role=banner]:hover {
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
footer .alignleft, footer .alignright {
|
||||
float: none;
|
||||
display: block;
|
||||
}
|
||||
footer .alignleft, footer .alignright {
|
||||
float: none;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1250,7 +1250,7 @@ nav ul {
|
||||
display: flex;
|
||||
-webkit-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
/*====align left====*/
|
||||
/*====align left====*/
|
||||
justify-content: flex-start;
|
||||
/* ==== align center ====*/
|
||||
/*justify-content: center; */
|
||||
@@ -1297,37 +1297,38 @@ nav.aligncenter ul, .aligncenter nav ul {
|
||||
}
|
||||
|
||||
nav.navbar ul li {
|
||||
/*====full float li a ====*/
|
||||
-webkit-flex: 1 1 auto;
|
||||
flex: 1 1 auto;
|
||||
/*====full float li a ====*/
|
||||
-webkit-flex: 1 1 auto;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
@media (max-width: 568px) {
|
||||
nav.navbar ul {
|
||||
nav.navbar ul {
|
||||
-webkit-flex-flow: column wrap;
|
||||
flex-flow: column wrap;
|
||||
padding: 0;
|
||||
}
|
||||
nav.navbar li a{justify-content:flex-start;
|
||||
}
|
||||
}
|
||||
nav.navbar li a {
|
||||
justify-content:flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
/*============================================
|
||||
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.*/
|
||||
|
||||
section * {
|
||||
-webkit-animation: fadeIn 0.3s ease-in-out;
|
||||
animation: fadeIn 0.3s ease-in-out;
|
||||
section * {
|
||||
-webkit-animation: fadeIn 0.3s ease-in-out;
|
||||
animation: fadeIn 0.3s ease-in-out;
|
||||
}
|
||||
section .background,section .background-video,
|
||||
[class*="background-"].light,[class*="background-"].dark {
|
||||
-webkit-animation-duration:0s;
|
||||
animation-duration:0s;
|
||||
-webkit-animation-duration:0s;
|
||||
animation-duration:0s;
|
||||
}
|
||||
|
||||
/*=== Section = Slide === */
|
||||
@@ -1349,17 +1350,17 @@ section,.slide
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
section, .slide {
|
||||
section, .slide {
|
||||
padding-top: 12rem;
|
||||
padding-bottom: 12rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*slide no padding (full card, .embed> youtube video...) */
|
||||
.fullscreen {
|
||||
padding: 0;
|
||||
/* Fixed/Visible header?
|
||||
padding:8.2rem 0 0 0;
|
||||
*/
|
||||
padding: 0;
|
||||
/* Fixed/Visible header?
|
||||
padding:8.2rem 0 0 0;
|
||||
*/
|
||||
}
|
||||
|
||||
/* 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-"]=== */
|
||||
|
||||
[class*="content-"] {
|
||||
@@ -1385,12 +1386,12 @@ padding:8.2rem 0 0 0;
|
||||
.wrap[class*="bg-"],.wrap.frame,
|
||||
[class*="content-"][class*="bg-"],
|
||||
[class*="content-"].frame, [class*="align"][class*="bg-"]{
|
||||
padding: 4.8rem;
|
||||
padding: 4.8rem;
|
||||
}
|
||||
|
||||
[class*="content-"] > [class*="content-"] p {
|
||||
font-size: 1.8rem;
|
||||
line-height: 3.2rem;
|
||||
font-size: 1.8rem;
|
||||
line-height: 3.2rem;
|
||||
}
|
||||
|
||||
.content-center {
|
||||
@@ -1399,7 +1400,7 @@ padding:8.2rem 0 0 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
[class*="content-"] {
|
||||
[class*="content-"] {
|
||||
width: 50%;
|
||||
}
|
||||
.content-left {
|
||||
@@ -1408,45 +1409,45 @@ padding:8.2rem 0 0 0;
|
||||
.content-right {
|
||||
float: right;
|
||||
}
|
||||
[class*="content-"] + [class*="content-"] {
|
||||
padding-left:2.4rem;
|
||||
[class*="content-"] + [class*="content-"] {
|
||||
padding-left:2.4rem;
|
||||
margin-bottom: 4.8rem;
|
||||
}
|
||||
[class*="content-"] + [class*="size-"] {
|
||||
margin-top: 6.4rem;
|
||||
clear:both;
|
||||
}
|
||||
}
|
||||
[class*="content-"] + [class*="size-"] {
|
||||
margin-top: 6.4rem;
|
||||
clear:both;
|
||||
}
|
||||
|
||||
[class*="content-"]:before,
|
||||
[class*="content-"]:after {
|
||||
[class*="content-"]:before,
|
||||
[class*="content-"]:after {
|
||||
content: "";
|
||||
display: table;
|
||||
}
|
||||
}
|
||||
|
||||
[class*="content-"]:after {
|
||||
[class*="content-"]:after {
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* === 5.2 Counter / Navigation Slides === */
|
||||
|
||||
#navigation {
|
||||
position: fixed;
|
||||
width: 24.4rem;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
/* hover/visibility */
|
||||
z-index: 3;
|
||||
position: fixed;
|
||||
width: 24.4rem;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
/* hover/visibility */
|
||||
z-index: 3;
|
||||
}
|
||||
#navigation {
|
||||
-webkit-animation: fadeIn 16s;
|
||||
animation: fadeIn 16s;
|
||||
opacity:0;
|
||||
-webkit-animation: fadeIn 16s;
|
||||
animation: fadeIn 16s;
|
||||
opacity:0;
|
||||
}
|
||||
#navigation:hover {
|
||||
opacity: 1;
|
||||
opacity: 1;
|
||||
}
|
||||
/* -- navigation arrow always visible? -- */
|
||||
|
||||
@@ -1489,14 +1490,14 @@ a#previous {
|
||||
left: 3.2rem;
|
||||
}
|
||||
@media (max-width:1024px) {
|
||||
#navigation {
|
||||
background: url('../images/swipe.svg') no-repeat center top;
|
||||
background-size: 4.8rem;
|
||||
-webkit-animation: fadeIn 6s;
|
||||
animation: fadeIn 6s;
|
||||
}
|
||||
#navigation a, #counter {display: none;
|
||||
}
|
||||
#navigation {
|
||||
background: url('../images/swipe.svg') no-repeat center top;
|
||||
background-size: 4.8rem;
|
||||
-webkit-animation: fadeIn 6s;
|
||||
animation: fadeIn 6s;
|
||||
}
|
||||
#navigation a, #counter {display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/*=== 5.3 Slides - Background Images === */
|
||||
@@ -1516,15 +1517,15 @@ animation: fadeIn 6s;
|
||||
background-size: cover
|
||||
}
|
||||
.background-top {
|
||||
background-position: top;
|
||||
background-size: cover;
|
||||
background-position: top;
|
||||
background-size: cover;
|
||||
}
|
||||
.background-bottom {
|
||||
background-position: bottom;
|
||||
background-size: cover;
|
||||
background-position: bottom;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
/*fullscreen video
|
||||
/*fullscreen video
|
||||
<video class="background-video">
|
||||
*/
|
||||
|
||||
@@ -1544,10 +1545,10 @@ background-size: cover;
|
||||
background-position: center top;
|
||||
}
|
||||
.background-right-top {
|
||||
background-position: right top;
|
||||
background-position: right top;
|
||||
}
|
||||
.background-left-top {
|
||||
background-position: left top;
|
||||
background-position: left top;
|
||||
}
|
||||
.background-center-bottom,
|
||||
.background-left-bottom,
|
||||
@@ -1556,8 +1557,8 @@ background-size: cover;
|
||||
background-position: center bottom;
|
||||
}
|
||||
|
||||
@media (min-width:1024px) {
|
||||
.background-left-bottom {
|
||||
@media (min-width:1024px) {
|
||||
.background-left-bottom {
|
||||
background-position: left bottom;
|
||||
}
|
||||
.background-right-bottom {
|
||||
@@ -1594,14 +1595,14 @@ background-size: cover;
|
||||
filter: alpha(opacity=5);
|
||||
}
|
||||
@media (max-width:1023px) {
|
||||
[class*="background-"] {
|
||||
opacity: 0.20;
|
||||
-webkit-animation: fadeIn ease-in 0.20;
|
||||
animation: fadeIn ease-in 0.20;
|
||||
}
|
||||
.background-video {
|
||||
opacity: 0.80;
|
||||
}
|
||||
[class*="background-"] {
|
||||
opacity: 0.20;
|
||||
-webkit-animation: fadeIn ease-in 0.20;
|
||||
animation: fadeIn ease-in 0.20;
|
||||
}
|
||||
.background-video {
|
||||
opacity: 0.80;
|
||||
}
|
||||
}
|
||||
/*=== Animated Background Image === */
|
||||
|
||||
@@ -1612,11 +1613,11 @@ background-size: cover;
|
||||
background-position: center top;
|
||||
-webkit-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)
|
||||
================================================================= */
|
||||
|
||||
@@ -1662,8 +1663,8 @@ Blocks Links li>a = .flexblock.blink (.blink required)
|
||||
transition: .3s;
|
||||
}
|
||||
.flexblock li:hover{
|
||||
-webkit-transform: translateY(-.2rem);
|
||||
transform: translateY(-.2rem);
|
||||
-webkit-transform: translateY(-.2rem);
|
||||
transform: translateY(-.2rem);
|
||||
}
|
||||
.flexblock.aligncenter li {text-align: center;}
|
||||
|
||||
@@ -1729,9 +1730,9 @@ div + ul, div + ol{
|
||||
width: 46%;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
.features li span,.features li svg {
|
||||
font-size: 6.4rem;
|
||||
line-height: 1;
|
||||
display: block;
|
||||
margin: 0;
|
||||
}
|
||||
font-size: 6.4rem;
|
||||
line-height: 1;
|
||||
display: block;
|
||||
margin: 0;
|
||||
}
|
||||
.features li img {width: 6.4rem;}
|
||||
|
||||
.features li span sup {
|
||||
font-size: 3rem;
|
||||
.features li span sup {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
@media (min-width:1200px) {
|
||||
@@ -1803,7 +1804,7 @@ div + ul, div + ol{
|
||||
}
|
||||
|
||||
.clients li:hover {
|
||||
z-index: 1;
|
||||
z-index: 1;
|
||||
}
|
||||
/*==================================================
|
||||
6.3 flexblock.steps <ul class="flexblock steps">
|
||||
@@ -1905,20 +1906,20 @@ About, Philosophy...
|
||||
}
|
||||
|
||||
.specs li span,.specs li svg {
|
||||
font-size: 6.4rem;
|
||||
line-height: 1;
|
||||
display: block;
|
||||
margin: 0;
|
||||
font-size: 6.4rem;
|
||||
line-height: 1;
|
||||
display: block;
|
||||
margin: 0;
|
||||
}
|
||||
.specs li img {width: 6.4rem;}
|
||||
|
||||
.specs li span {
|
||||
font-weight: 300;
|
||||
|
||||
font-weight: 300;
|
||||
|
||||
}
|
||||
.specs li span sup {
|
||||
font-size: 3rem;
|
||||
|
||||
font-size: 3rem;
|
||||
|
||||
}
|
||||
|
||||
@media (min-width:1024px) {
|
||||
@@ -1934,18 +1935,18 @@ About, Philosophy...
|
||||
=================================================== */
|
||||
|
||||
.flexblock.reasons li {
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
counter-increment: list;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
counter-increment: list;
|
||||
}
|
||||
.reasons li:hover{
|
||||
-webkit-transform: translateY(-.2rem);
|
||||
transform: translateY(-.2rem);
|
||||
-webkit-transform: translateY(-.2rem);
|
||||
transform: translateY(-.2rem);
|
||||
}
|
||||
.reasons li:before {
|
||||
content: counter(list)'.';
|
||||
font-size: 6.4rem;
|
||||
line-height: 1;
|
||||
content: counter(list)'.';
|
||||
font-size: 6.4rem;
|
||||
line-height: 1;
|
||||
}
|
||||
.reasons li:after {
|
||||
position: relative;
|
||||
@@ -1955,12 +1956,12 @@ transform: translateY(-.2rem);
|
||||
display: block;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.reasons li {
|
||||
padding-left: 8.8rem;
|
||||
.reasons li {
|
||||
padding-left: 8.8rem;
|
||||
/* You need two digits? (1-10)*/
|
||||
/*padding-left: 12rem; */
|
||||
}
|
||||
.reasons li:before {
|
||||
}
|
||||
.reasons li:before {
|
||||
position: absolute;
|
||||
left: 2.4rem;
|
||||
}
|
||||
@@ -1968,7 +1969,7 @@ transform: translateY(-.2rem);
|
||||
|
||||
/*=================================================
|
||||
6.7 Gallery - <ul class="flexblock gallery">
|
||||
Block Thumbnails li+.overlay+image
|
||||
Block Thumbnails li+.overlay+image
|
||||
img size recommended:800x600px
|
||||
=================================================== */
|
||||
|
||||
@@ -2011,7 +2012,7 @@ img size recommended:800x600px
|
||||
transition: .1s;
|
||||
}
|
||||
.gallery li:hover figcaption:before {
|
||||
top:.3rem;
|
||||
top:.3rem;
|
||||
}
|
||||
.aligncenter .gallery li figcaption:before {
|
||||
margin-left: 0;
|
||||
@@ -2019,9 +2020,9 @@ top:.3rem;
|
||||
}
|
||||
|
||||
.gallery li footer {
|
||||
position: relative;
|
||||
padding:1.2rem 0 0;
|
||||
margin-top: .8rem;
|
||||
position: relative;
|
||||
padding:1.2rem 0 0;
|
||||
margin-top: .8rem;
|
||||
}
|
||||
@media (min-width:600px) {
|
||||
.flexblock.gallery {
|
||||
@@ -2072,16 +2073,16 @@ margin-top: .8rem;
|
||||
justify-content: center;
|
||||
transition: all 0.3s linear;
|
||||
}
|
||||
li .overlay {
|
||||
align-items: center;
|
||||
li .overlay {
|
||||
align-items: center;
|
||||
}
|
||||
li .overlay h2 {
|
||||
text-transform: uppercase;
|
||||
margin: 0;
|
||||
padding: 0 2.4rem;
|
||||
letter-spacing: .2rem;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
margin: 0;
|
||||
padding: 0 2.4rem;
|
||||
letter-spacing: .2rem;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.overlay p,
|
||||
@@ -2181,7 +2182,7 @@ li:hover .overlay {
|
||||
|
||||
/*===========================================
|
||||
6.9 Block Activity <ul class="activity">
|
||||
CV / News
|
||||
CV / News
|
||||
============================================= */
|
||||
|
||||
.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 === */
|
||||
|
||||
@media (min-width: 768px) {
|
||||
@@ -2896,7 +2897,7 @@ select {
|
||||
padding: .7rem;
|
||||
font-weight: 400;
|
||||
font-size: 1.6rem;
|
||||
|
||||
|
||||
}
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
@@ -2932,7 +2933,7 @@ button {
|
||||
}
|
||||
|
||||
.button.radius, button.radius,input.radius {border-radius: 2.4rem;}
|
||||
|
||||
|
||||
button,
|
||||
input[type="submit"] {
|
||||
text-transform: uppercase;
|
||||
@@ -2991,11 +2992,11 @@ select:focus {
|
||||
}
|
||||
|
||||
@media (min-width:1024px) {
|
||||
[class*="badge-"] {
|
||||
width: 162px;
|
||||
height: 48px;
|
||||
line-height: 4.8rem;
|
||||
}
|
||||
[class*="badge-"] {
|
||||
width: 162px;
|
||||
height: 48px;
|
||||
line-height: 4.8rem;
|
||||
}
|
||||
}
|
||||
.badge-ios {
|
||||
background-image: url("../images/bt-appstore.png");
|
||||
@@ -3011,8 +3012,8 @@ select:focus {
|
||||
a.button:hover,
|
||||
button[type="submit"]:hover,
|
||||
input[type="submit"]:hover {
|
||||
-webkit-transform:scale(1.01);
|
||||
transform: scale(1.01);
|
||||
-webkit-transform:scale(1.01);
|
||||
transform: scale(1.01);
|
||||
}
|
||||
[class*="badge-"]:hover {
|
||||
opacity: 0.7;
|
||||
@@ -3048,14 +3049,14 @@ transform: scale(1.01);
|
||||
cursor: pointer;
|
||||
}
|
||||
[class*="button"] + [class*="button"],[class*="badge"] + [class*="badge"] {
|
||||
margin-left: 1.8rem;
|
||||
margin-left: 1.8rem;
|
||||
}
|
||||
}
|
||||
@media (max-width:499px) {
|
||||
|
||||
[class*="button"] + [class*="button"],[class*="badge"] + [class*="badge"] {
|
||||
margin-top: .8rem;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -81,27 +81,27 @@ hr:after {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
bbbr,
|
||||
abbr,
|
||||
acronym {
|
||||
border-bottom: 1px dotted #333;
|
||||
}
|
||||
|
||||
mark,
|
||||
ins {
|
||||
background-color: rgba(221,238,255, 0.8);
|
||||
color: inherit;
|
||||
background-color: rgba(221,238,255, 0.8);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
background-color: rgba(221,238,255, 0.8);
|
||||
background-color: rgba(221,238,255, 0.8);
|
||||
}
|
||||
|
||||
::-webkit-selection {
|
||||
background-color: rgba(221,238,255, 0.8);
|
||||
background-color: rgba(221,238,255, 0.8);
|
||||
}
|
||||
|
||||
::selection {
|
||||
background-color: rgba(221,238,255, 0.8);
|
||||
background-color: rgba(221,238,255, 0.8);
|
||||
}
|
||||
|
||||
pre {
|
||||
@@ -119,7 +119,7 @@ code,[class*="bg-"] pre {
|
||||
}
|
||||
|
||||
.bg-white code{
|
||||
background: rgba(0, 20, 80, 0.03);
|
||||
background: rgba(0, 20, 80, 0.03);
|
||||
}
|
||||
/*================================================
|
||||
Slides - Backgrounds <section class="bg-primary">
|
||||
@@ -218,7 +218,7 @@ Slides - Backgrounds <section class="bg-primary">
|
||||
|
||||
/*Covers/Longforms...*/
|
||||
.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*/
|
||||
@@ -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)*/
|
||||
.bg-gradient-gray{
|
||||
background: linear-gradient(90deg,#f7f9fb 0,#dee2e6 100%);
|
||||
color: #333;
|
||||
text-shadow: none;
|
||||
background: linear-gradient(90deg,#f7f9fb 0,#dee2e6 100%);
|
||||
color: #333;
|
||||
text-shadow: none;
|
||||
}
|
||||
/*Border/Frame*/
|
||||
.frame {
|
||||
@@ -261,7 +261,7 @@ text-shadow: none;
|
||||
|
||||
/*Layer/Box Shadow*/
|
||||
.shadow,.pre {
|
||||
position: relative;
|
||||
position: relative;
|
||||
}
|
||||
.shadow:before,.shadow:after {
|
||||
box-shadow: 0 16px 24px rgba(0, 20, 80, 0.3);
|
||||
@@ -274,13 +274,13 @@ TYPOGRAPHY
|
||||
/* -- Horizontal separator -- */
|
||||
|
||||
.text-separator:before {
|
||||
background-color: rgba(170, 0, 0, 0.8);
|
||||
background-color: rgba(170, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
/* -- Pull Quote (Right/Left) -- */
|
||||
|
||||
[class*="text-pull-"] {
|
||||
border-top: 4px solid rgba(0, 0, 0, 0.5);
|
||||
border-top: 4px solid rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
/* -- Context -- */
|
||||
|
||||
@@ -374,7 +374,7 @@ nav li.email a:hover {
|
||||
}
|
||||
|
||||
/*=========================================
|
||||
Features & Clients List
|
||||
Features & Clients List
|
||||
=========================================== */
|
||||
|
||||
.features li,.clients li {
|
||||
@@ -387,7 +387,7 @@ Features & Clients List
|
||||
}
|
||||
|
||||
.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;}*/
|
||||
|
||||
@@ -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) {
|
||||
@@ -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);
|
||||
}
|
||||
.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 {
|
||||
@@ -684,7 +684,7 @@ Cards
|
||||
/*== Figure Background === */
|
||||
|
||||
[class*="card-"][class*="bg-"] figure {
|
||||
background-color: rgba(0, 20, 80, 0.06);
|
||||
background-color: rgba(0, 20, 80, 0.06);
|
||||
}
|
||||
|
||||
/*== 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%;
|
||||
-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%;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -737,7 +737,7 @@ tr:nth-child(even)>td:hover {
|
||||
|
||||
|
||||
/*============================
|
||||
Browser (Screenshots)
|
||||
Browser (Screenshots)
|
||||
============================== */
|
||||
|
||||
.browser {
|
||||
@@ -783,10 +783,10 @@ input:focus::-moz-placeholder {
|
||||
input:focus::-webkit-input-placeholder {
|
||||
color: #ddd;
|
||||
}
|
||||
a.button,[class*="badge-"]
|
||||
a.button,[class*="badge-"],
|
||||
button[type="submit"],
|
||||
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,
|
||||
@@ -797,7 +797,7 @@ button[type="submit"],
|
||||
input[type="submit"],
|
||||
.button,.button:hover,
|
||||
button[type="submit"]:hover,
|
||||
input[type="submit"]:hover
|
||||
input[type="submit"]:hover
|
||||
{
|
||||
border: 1px solid #44d;
|
||||
}
|
||||
@@ -810,7 +810,7 @@ input[type="submit"],
|
||||
text-shadow: 0 1px 0 #123;
|
||||
}
|
||||
.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;}
|
||||
.bg-primary select,
|
||||
@@ -818,7 +818,7 @@ background-color: #17d;
|
||||
.bg-primary .button,
|
||||
.bg-primary button,.bg-primary button:hover,
|
||||
.bg-primary input,
|
||||
[class*="bg-gradient-"] .button,[class*="bg-"] a.button.ghost
|
||||
[class*="bg-gradient-"] .button,[class*="bg-"] a.button.ghost
|
||||
{
|
||||
border-color: #fff;
|
||||
}
|
||||
|
@@ -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)?'↓':'→',
|
||||
previous : $slideshow.hasClass(obj.settings.verticalClass)?'↑':'←',
|
||||
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
27
webpack.config.babel.js
Normal 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
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user