1
0
mirror of https://github.com/webslides/WebSlides.git synced 2025-09-10 05:00:40 +02:00

Compare commits

...

220 Commits

Author SHA1 Message Date
Luis Sacristán
9ec4fae96b Merge pull request #166 from webslides/dependabot/npm_and_yarn/node-sass-4.13.1
Bump node-sass from 4.9.4 to 4.13.1
2020-09-05 22:55:37 +02:00
dependabot[bot]
13cfd525e8 Bump node-sass from 4.9.4 to 4.13.1
Bumps [node-sass](https://github.com/sass/node-sass) from 4.9.4 to 4.13.1.
- [Release notes](https://github.com/sass/node-sass/releases)
- [Changelog](https://github.com/sass/node-sass/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sass/node-sass/compare/v4.9.4...v4.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-09-03 23:08:31 +00:00
Antonio Laguna
fb5208218f Ensuring tests pass again
Fixes #131
2019-02-19 19:06:13 +01:00
Antonio Laguna
87db22523c Merge pull request #115 from AragurDEV/patch-1
Fix 404 in README.md
2018-08-10 14:28:09 +02:00
AragurDEV
d9c2cb44f8 Fix 404 in README.md
Directly accessing 'wiki' results in a 404.
I have added the complete wiki url (as in the FAQ topic)
2018-08-10 14:00:29 +02:00
Antonio Laguna
9a2dfe0e52 Merge pull request #106 from oligot/no-babelrc
Don't publish .babelrc file
2018-01-23 15:27:10 +01:00
Olivier Ligot
26716804cb Don't publish .babelrc file
More and more npm packages contain ES2015+ code.
As discussed in [this AMA](https://github.com/sindresorhus/ama/issues/446), this causes a lot of troubles (Uglify and old browsers) for people.

One possible solution is to transpile external dependencies, as discussed in [this issue on create-react-app](https://github.com/facebookincubator/create-react-app/issues/1125) and implemented in [this pull request](https://github.com/facebookincubator/create-react-app/pull/3776).

This doesn't currently work with Webslides as the .babelrc file is published on npm.
Here is a [small repo demonstrating the bug](https://github.com/oligot/webslides-babelrc).
Running `npm run build` results in this error

```
ERROR in ./node_modules/webslides/static/js/webslides.js
Module build failed: Error: Couldn't find preset "es2015" relative to directory ".../webslides-babelrc/node_modules/webslides"
```

By adding the .babelrc file to .npmignore, and removing the babel config in the _package.json_ file, the bug would go away once a new version of Webslides is published.

This is basically the same PR as done for [v-tooltip](https://github.com/Akryum/v-tooltip/pull/90).
2018-01-23 13:51:25 +01:00
Antonio Laguna
ea0f2cb833 Adding a way to go to sections by id
#71
2018-01-01 16:32:35 +01:00
Antonio Laguna
5dd1b9c649 Firing show event on the slide
Fixes #104
2018-01-01 16:03:32 +01:00
Antonio Laguna
ed93fd8df9 Adapting to changes to JSDOM 2018-01-01 16:01:49 +01:00
Antonio Laguna
43105bd180 Updating dependencies 2018-01-01 16:00:42 +01:00
Antonio Laguna
bee1e87c7f Events now bubble by default 2018-01-01 15:37:35 +01:00
José Luis Antúnez
e9fa8d2e3a adding codepen account 2017-09-18 11:14:24 +02:00
Antonio Laguna
13fe06daa8 1.5.0
Fixes #96 #97
2017-09-16 22:45:19 +02:00
Antonio Laguna
eef9d75706 Fixing package.json 2017-09-16 22:32:11 +02:00
Antonio Laguna
b1e03202e3 Adding version scripts 2017-09-16 22:29:34 +02:00
Antonio Laguna
3b7203c9ab Ctrl/Cmd + F should not trigger fullscreen
Hence allowing search
#97
2017-09-16 19:45:13 +02:00
Antonio Laguna
8912d05d70 Shift + Space should go backwards
#96
2017-09-16 19:37:24 +02:00
Antonio Laguna
8b19bd28f6 Updating deps 2017-09-16 19:37:03 +02:00
Antonio Laguna
71f2fd52b9 1.4.2 2017-09-12 10:16:05 +02:00
Antonio Laguna
fe58531e74 Removing unneeded class 2017-09-12 10:14:17 +02:00
Luis Sacristán
71b08f8d3b Fixing TOC 2017-09-03 19:30:05 +02:00
Antonio Laguna
e8dc32e274 1.4.1 2017-08-18 10:43:37 +02:00
Antonio Laguna
1610da683e Merge branch 'dev' 2017-08-18 10:37:56 +02:00
José Luis Antúnez
5233851f59 fixing longform alignments 2017-08-15 19:51:59 +02:00
José Luis Antúnez
eb58c83d11 header: changing the link on the logo 2017-08-15 19:50:02 +02:00
José Luis Antúnez
253e087c15 a new unsplash photo 2017-08-15 19:48:13 +02:00
José Luis Antúnez
ce4b1603d2 updating demos
header logo and a new unsplash photo
2017-08-15 19:48:05 +02:00
José Luis Antúnez
514df1b421 fixing longform alignments 2017-08-15 12:12:25 +02:00
Antonio Laguna
eb402a886f 1.4.0
Fixes #88 #52 #66 #73 #84
2017-08-14 13:17:01 +02:00
Antonio Laguna
03603fa1c8 Merge branch 'master' into dev
# Conflicts:
#	src/js/utils/scroll-to.js
2017-08-14 13:12:31 +02:00
Luis Sacristán
261259a9d3 Fixing brown color 2017-08-13 18:02:15 +02:00
Luis Sacristán
37d9b84bff Fixing scrolling after zooming 2017-08-11 23:20:08 +02:00
Luis Sacristán
e6de10e449 Fixing document.scrollingElement not working in Firefox 2017-08-10 22:34:53 +02:00
José Luis Antúnez
fc1a733d6f removing bg image (slide 3) 2017-08-10 10:53:52 +02:00
Luis Sacristán
e523998f1e Fixing minus and plus buttons for index in Chrome 2017-08-06 12:50:52 +02:00
Luis Sacristán
6699407c08 Prevent Firefox keypress default event, it produced to scroll the page up/down 2017-08-05 01:48:01 +02:00
Luis Sacristán
18970a7b7b Fixing navigator test 2017-08-04 21:49:18 +02:00
Luis Sacristán
e39fad9a16 Removing counter link when index is disabled #88 2017-08-04 20:04:57 +02:00
Luis Sacristán
e78e25ddea Fixing zoom tests 2017-08-02 22:15:33 +02:00
Luis Sacristán
f4c93e68d3 Adding new showIndex option to WebSlides class 2017-08-02 21:41:46 +02:00
José Luis Antúnez
94e8e22f10 fixing a bg image: removing parenthesis in the URL 2017-08-02 22:43:56 +02:00
Luis
4462883dc0 Fixing gallery css 2017-08-02 11:33:32 +02:00
Luis
2c2fd3a0db Changing index background, removing blur effect #88 2017-08-01 17:44:49 +02:00
Antonio Laguna
cfd1f74b9b 1.3.3 2017-07-29 13:20:59 +02:00
Antonio Laguna
7bcafd9f7c Fixing scrollable container in run time 2017-07-29 13:20:03 +02:00
Antonio Laguna
50cb44c85f Build 2017-07-28 11:54:48 +02:00
Antonio Laguna
eea1b46f02 Adjustments for zoom 2017-07-28 11:54:40 +02:00
Antonio Laguna
cf4f1d22b7 Typo 2017-07-28 11:20:33 +02:00
Antonio Laguna
9f93263c86 Using class to control overflow 2017-07-28 11:20:21 +02:00
Antonio Laguna
4fb3f14cde Pointing to correct main 2017-07-28 11:20:03 +02:00
Antonio Laguna
31dc31c307 Updating deps 2017-07-28 10:43:24 +02:00
Luis
cb60cab236 Improving index slidex sizes 2017-07-24 20:28:44 +02:00
Luis
5226ab189b Fixing demos styles path 2017-07-17 10:21:05 +02:00
Luis
5456109a97 Fixing zoom test 2017-07-17 00:24:48 +02:00
Luis
578a66977a Improving index rendering, first approach 2017-07-16 20:18:04 +02:00
Luis
0e0b2b4160 Fixing index responsive slide sizes 2017-07-15 14:28:44 +02:00
Luis
c109276ef6 Scrolling to current slide when index is shown 2017-07-14 23:32:15 +02:00
Luis
98886a159f Fixing back blured layer made scroll not accesible 2017-07-13 19:13:53 +02:00
Luis Sacristán
d042984f5d Slides index: new current slide style 2017-07-10 21:45:47 +02:00
Luis
a720b6b5fb Fixing some tests 2017-06-29 14:22:06 +02:00
Luis
8e75227ea0 Fixing wheel delta in Firefox 2017-06-29 11:33:01 +02:00
Antonio Laguna
811007da8d Adding some transitioning to zoom 2017-06-28 16:56:53 +02:00
Antonio Laguna
377de1f0be Fixing issues 2017-06-28 16:12:26 +02:00
Antonio Laguna
43bc612a5b No autosliding if zoom gets enabled 2017-06-28 14:55:42 +02:00
José Luis Antúnez
9256c476b9 header nav li a: color #fff 2017-06-28 11:33:17 +02:00
José Luis Antúnez
654510a374 reordering modules: zoom and print 2017-06-28 10:38:03 +02:00
Luis Sacristán
118417b215 Changes in zoom, it doesn't use javascript sizes 2017-06-28 00:30:38 +02:00
José Luis Antúnez
c997ec6cc4 .wrap paddings: top/bottom: 12rem 2017-06-22 11:25:08 +02:00
José Luis Antúnez
0b4c458203 .wrap: removing width 100%, padding: 12rem 0 2017-06-22 11:23:56 +02:00
José Luis Antúnez
ea8a839dc8 removing color: .wrap-zoom.current 2017-06-22 11:07:21 +02:00
José Luis Antúnez
ab63347ef3 adding comments 2017-06-22 10:54:57 +02:00
José Luis Antúnez
7fda1f4de9 adding comments 2017-06-22 10:54:08 +02:00
Luis
63ac064a25 Fixing zoom test 2017-06-21 17:26:51 +02:00
Luis
5b45de0b79 Changes in slides index, adding padding, current slide, ... 2017-06-21 16:48:35 +02:00
Antonio Laguna
e7329433ff Minor touches 2017-06-17 16:37:56 +02:00
Antonio Laguna
db95f1bf0c Updating libraries 2017-06-17 16:27:02 +02:00
Antonio Laguna
2c0f82d942 Linting 2017-06-17 16:27:02 +02:00
Antonio Laguna
da61aed18b Adding default animationEnd to play nice with JSDom 2017-06-17 16:27:02 +02:00
Antonio Laguna
05db02495c Adding more tests to webslides 2017-06-17 16:27:01 +02:00
Antonio Laguna
fedad97769 Merge pull request #84 from solilokiam/create-fullscreen-key
Fullscreen mode
2017-06-06 18:24:30 +02:00
Antonio Laguna
3e64e33ed7 Refactor Slide test 2017-06-06 17:25:25 +02:00
Miquel Company Rodriguez
18662f38f6 Cleaner fullscreen function test 2017-06-06 16:30:19 +02:00
Miquel Company Rodriguez
af13de6696 Add tests to fullscreen function 2017-06-06 16:26:40 +02:00
Miquel Company Rodriguez
504ad99df9 Standarize the order of the prefixed 2017-06-06 16:09:23 +02:00
Miquel Company Rodriguez
6f79bce0de Add keyboard test 2017-06-06 15:53:52 +02:00
Miquel Company Rodriguez
52e9188b55 Go to fullscreen when f key is pressed 2017-06-06 15:53:52 +02:00
Antonio Laguna
bad0ef5551 Linting 2017-06-06 15:47:56 +02:00
Antonio Laguna
12d7608dbb No more legacy 2017-06-06 15:47:50 +02:00
Antonio Laguna
893229ba1c Finishing tests on DOM 2017-06-06 15:45:39 +02:00
Antonio Laguna
d34e445e7c Updating deps 2017-06-06 15:45:39 +02:00
Antonio Laguna
2f292cc5ee No more node 8 for now 2017-06-06 15:45:39 +02:00
José Luis Antúnez
54589277b7 adding typography comments 2017-06-05 12:53:34 +02:00
Luis
5160ce05ef Sass: reordening modules 2017-06-02 09:19:56 +02:00
Luis
810b634477 Sass - fixing right side of the .shadow 2017-06-02 00:08:04 +02:00
Luis
9c06479d9d Fixing size-n width 2017-06-02 00:03:00 +02:00
Luis
0e54ccc4a2 Sass: adding SVG icons size 2017-06-01 23:53:57 +02:00
Luis
aa71fe97bc Sass Slides index 2017-06-01 23:30:20 +02:00
Antonio Laguna
8773012e0d Locking 2017-06-01 17:47:35 +02:00
Antonio Laguna
dad3957cf3 Building again 2017-06-01 17:47:26 +02:00
José Luis Antúnez
db177cf405 fixing comment (block number) 2017-06-01 11:42:23 +02:00
José Luis Antúnez
e447935c3c reordering blocks and adding comments 2017-06-01 11:40:23 +02:00
Antonio Laguna
ac80c7afec Proper percent 2017-06-01 10:48:23 +02:00
Antonio Laguna
86894f0489 Updating query 2017-06-01 10:41:30 +02:00
Antonio Laguna
eb515bbcb7 Built JS 2017-05-31 20:42:01 +02:00
Antonio Laguna
aa1afb2927 Built CSS 2017-05-31 20:41:44 +02:00
Antonio Laguna
a2100eabdb Linting 2017-05-31 20:41:29 +02:00
José Luis Antúnez
b2b761f5b1 adding li 2017-05-31 11:42:04 +02:00
José Luis Antúnez
caeacda724 Adding comments & Changing order 2017-05-31 11:35:34 +02:00
Antonio Laguna
ac8ac17490 Let’s test on Node 8 now 2017-05-31 08:25:45 +02:00
displaynone
f525d7ec87 Merge branch 'dev' of https://github.com/webslides/WebSlides into dev 2017-05-30 01:26:27 +02:00
displaynone
aa15d18dca Hash test at 100% 2017-05-30 01:25:39 +02:00
Antonio Laguna
26281751ec Testing love 2017-05-29 23:35:05 +02:00
Antonio Laguna
ed9c3142b4 Removing unused code 2017-05-29 22:48:44 +02:00
Antonio Laguna
e3b9febbe0 Removing unneeded trickery 2017-05-29 22:48:17 +02:00
Antonio Laguna
408bd4e269 Minor JS update 2017-05-29 10:24:45 +02:00
Antonio Laguna
34495579c0 Adding some comments 2017-05-29 10:24:29 +02:00
Antonio Laguna
c04825878d Allowing comments 2017-05-29 10:24:03 +02:00
Antonio Laguna
6a61ddbcf4 Lint before build 2017-05-29 10:23:55 +02:00
Antonio Laguna
c5ee83c940 Linting 2017-05-29 10:16:40 +02:00
Antonio Laguna
8a9ea037c0 Linting pre-commit 2017-05-29 09:24:06 +02:00
Antonio Laguna
1d8ea0f48f Eslint cache is now ignored 2017-05-29 09:23:20 +02:00
Antonio Laguna
7ff8612c3f Warns to errors 2017-05-29 09:23:09 +02:00
Antonio Laguna
226388b209 Linting 2017-05-29 09:22:58 +02:00
Antonio Laguna
f92718e381 Updating things 2017-05-29 09:09:57 +02:00
Antonio Laguna
66a95ea75a Adding coverage badge 2017-05-29 07:54:31 +02:00
Antonio Laguna
3d236c518a Adding coverage 2017-05-29 07:52:43 +02:00
Antonio Laguna
0e2a4a9587 Updating devs 2017-05-29 07:39:42 +02:00
Antonio Laguna
891396ef52 Merge branch 'sass' into dev
# Conflicts:
#	package.json
#	static/css/base.css
#	static/css/legacy/colors.css
#	static/js/webslides.js
#	static/js/webslides.min.js
2017-05-29 07:37:49 +02:00
Antonio Laguna
d3b7032c48 Compiling 2017-05-29 07:36:37 +02:00
Antonio Laguna
b1b081038c Import all the things 2017-05-29 00:26:27 +02:00
Antonio Laguna
a5583beec6 Colors now in too 2017-05-29 00:24:57 +02:00
Antonio Laguna
f46de277c0 Restoring 2017-05-28 23:36:14 +02:00
Antonio Laguna
41f93fba25 Finishing 2017-05-28 23:34:46 +02:00
Antonio Laguna
e91a255560 Slide-bg 2017-05-28 23:26:33 +02:00
Antonio Laguna
d997593fd2 Flexblocks 2017-05-28 23:26:26 +02:00
displaynone
8e6b609068 New test: webslides 2017-05-23 21:04:18 +02:00
Antonio Laguna
50a1387fe1 Batch to Sass 2017-05-23 17:24:11 +02:00
displaynone
73ee831593 New test: Slide 2017-05-16 00:10:31 +02:00
displaynone
dbc06fedbb Reorganizing tests 2017-05-15 22:53:28 +02:00
displaynone
c82fd6507a Reorganizing tests 2017-05-15 15:26:48 +02:00
displaynone
2fb8c1e816 New test: Zoom 2017-05-15 15:02:16 +02:00
displaynone
7c1f07b575 New test: Youtube 2017-05-15 12:37:08 +02:00
displaynone
2e373c1d1c New test: Video 2017-05-10 21:18:54 +02:00
displaynone
a43b919c05 New test: Touch 2017-05-09 23:58:39 +02:00
displaynone
54facec8e5 New test: scroll 2017-05-08 01:31:25 +02:00
displaynone
d173a1fd54 New test: Navigation 2017-05-06 16:57:03 +02:00
Luis
f0a67fbc53 Fix createNode adding id when is empty 2017-05-06 13:17:28 +02:00
José Luis Antúnez
d150b00014 text-slide-number: color, removing text-shadow... 2017-05-06 12:53:47 +02:00
José Luis Antúnez
e3938e9451 slides index: adding .wrap 2017-05-06 12:52:07 +02:00
displaynone
fb6fdb1d57 New test: Keyboard 2017-05-05 23:47:07 +02:00
Luis
218c67a435 Changing zoom structure, now webslides-zoom > wrap > grid > colunms 2017-05-05 19:29:36 +02:00
displaynone
bc3d1a9fa0 New test: Hash 2017-05-04 23:40:41 +02:00
displaynone
65a4a47f22 New test: click nav 2017-05-03 23:52:05 +02:00
displaynone
466b92a7e4 Cleaning package 2017-05-03 00:28:21 +02:00
displaynone
7d0208f046 New tests: scrollTo and autoslide 2017-05-03 00:06:29 +02:00
Antonio Laguna
05b46fc11b Legacying 2017-05-01 12:54:40 +02:00
Antonio Laguna
fab63a99ca Merge branch 'CKGrafico-feature/sass' into sass
# Conflicts:
#	package.json
#	static/js/webslides.js
#	static/js/webslides.min.js
2017-05-01 12:52:38 +02:00
Antonio Laguna
48b40c6ae9 Housekeeping 2017-04-29 23:02:31 +02:00
Antonio Laguna
7f3af9672c Fixing typo 2017-04-29 23:00:51 +02:00
Antonio Laguna
6e27dc809a Housekeeping 2017-04-29 22:52:38 +02:00
Antonio Laguna
db0955305b Broadening the utility 2017-04-29 22:52:33 +02:00
Antonio Laguna
d2e6f562f2 Avoiding type coercion 2017-04-29 22:52:11 +02:00
Antonio Laguna
f954ea2fb3 Using util 2017-04-29 22:51:35 +02:00
Antonio Laguna
d1840ec016 Parens normalisation 2017-04-29 22:51:03 +02:00
Luis
1de7249a65 Merge branch 'dev' of https://github.com/webslides/WebSlides into dev 2017-04-29 12:49:00 +02:00
Luis
98d6095916 Slide number using a <p> 2017-04-29 12:48:46 +02:00
José Luis Antúnez
cb622727d6 slides index 2017-04-29 12:34:24 +02:00
José Luis Antúnez
c0a3d725df css comments: summary 2017-04-29 12:32:54 +02:00
Luis
0a19f0d813 Fix index background scroll and zoom out when clicking in bottom empty space 2017-04-29 12:28:37 +02:00
Luis
338b265950 Fix bad merging 2017-04-29 12:17:38 +02:00
Luis
b19e4a4e0d Slides index (aka zoom) merged into dev #73 2017-04-29 12:00:10 +02:00
Luis
37e8d1ae26 Blur effect 2017-04-29 11:41:37 +02:00
José Luis Antúnez
714915002c New first paragraph 2017-04-27 23:16:22 +02:00
José Luis Antúnez
fed6f1b932 "what's in the download" at the beginning 2017-04-27 23:05:13 +02:00
Antonio Laguna
786db33861 Adding missing option 2017-04-27 16:56:18 +02:00
Antonio Laguna
c894759d93 Linting 2017-04-27 16:44:47 +02:00
Antonio Laguna
7f59470ddd Adding option to disable scroll navigation
Fixes #66
2017-04-27 16:39:19 +02:00
Antonio Laguna
8b8dfb3c16 Merge branch 'jest' into dev
# Conflicts:
#	package.json
2017-04-27 16:30:50 +02:00
Antonio Laguna
eb45889266 Adding travis 2017-04-27 07:42:06 +02:00
Antonio Laguna
b6a4ae71b9 Adding tests with jest 2017-04-26 23:11:56 +02:00
Luis
ff4029dbef Fix touch events 2017-04-26 21:31:50 +02:00
Luis
4be762c6c0 Blur efect when zooming 2017-04-26 20:09:57 +02:00
Luis
c8244e32f5 Merge branch 'dev' of https://github.com/webslides/WebSlides into dev 2017-04-26 18:35:31 +02:00
Luis
0d1769d920 New test: goPrev 2017-04-26 18:35:07 +02:00
Antonio Laguna
bfa6901909 Updating dependencies 2017-04-25 20:02:47 +02:00
Luis
7299f5a6dd New test: goNext, testing after waiting some ms 2017-04-25 19:47:40 +02:00
Luis
71e7913a64 Tests now load repository web 2017-04-24 16:04:37 +02:00
Luis
68eae7952a Merge branch 'dev' of https://github.com/webslides/WebSlides into dev 2017-04-23 21:53:31 +02:00
Luis
72a73f700e Refactoring tests 2017-04-23 21:53:03 +02:00
Luis
e5ff650e07 New test: Has only one slide visible 2017-04-23 18:08:56 +02:00
Luis
98717b15a4 New test: has slides 2017-04-23 18:04:58 +02:00
Luis
17cb40e21b New test: first slide visible 2017-04-23 18:01:56 +02:00
Luis
d69046b670 Fix previous tests and new test: webslides object exists 2017-04-23 17:58:10 +02:00
Luis
d04d53a1ec Working testing using PhantomJS, previous ones wasn't good enough 2017-04-23 17:24:39 +02:00
José Luis Antúnez
a564e28d9a last slide: .text-emoji (smiling face) 2017-04-20 15:26:50 +02:00
Luis
95157d582a ESC key for zoom out 2017-04-18 20:34:45 +02:00
Luis
4dde8fe8fb Fix zoom out when click outside index slides 2017-04-18 20:29:09 +02:00
Luis
344b018db6 Fix some resolutions height 2017-04-14 18:28:27 +02:00
Luis
04bb9145a9 Zoom - pinch gesture 2017-04-13 18:47:01 +02:00
Luis
5a7c84891a Fix responsive zoom for some resolutions 2017-04-13 16:17:43 +02:00
Luis
b41cf41ac9 Zoom responsive 2017-04-12 21:25:20 +02:00
José Luis Antúnez
052772be98 index of slides: mini-slides same bg color as body 2017-04-09 20:19:48 +02:00
José Luis Antúnez
34fdc56eac index of slides: min 100vh, hover, numbers... 2017-04-09 19:47:54 +02:00
Luis
708d5bfda6 Zoom mode: unstyled slide number and zoom out when click outside the slide 2017-04-09 16:37:25 +02:00
Luis
89e8ffdd78 Fix navigation previous link 2017-04-08 14:01:40 +02:00
José Luis Antúnez
a49568a6b0 hover counter link, .gallery li (equal), longform 2017-04-08 13:52:21 +02:00
Luis
78ababde67 Fix counter link 2017-04-08 13:14:25 +02:00
Luis
ee6e0045e5 Adding zoom toggle to navigation counter 2017-04-08 11:20:17 +02:00
Luis
ebb5e9a4cd Click on zoomed slide event handled 2017-04-05 19:13:38 +02:00
Luis
79ec99a2f7 New implementation: webslides clone 2017-04-01 14:40:22 +02:00
Luis
eed75b0eb2 First version zoom 2017-03-31 18:16:03 +02:00
Luis
0768afe146 First version zoom 2017-03-31 18:15:35 +02:00
Quique Fdez Guerra
4248f08ae8 Delete webslides.min.js 2017-03-07 08:11:17 +01:00
Quique Fdez Guerra
f36bc93efb Delete webslides.js 2017-03-07 08:11:06 +01:00
Quique Fdez Guerra
ac5427f655 Delete webslides.min.css 2017-03-07 08:10:47 +01:00
Quique Fdez Guerra
13160c4131 Delete webslides.css 2017-03-07 08:10:35 +01:00
Quique Fdez Guerra
a43a84829a Refactor web pack configuration and remove webpack.config.babel because you are not using import A form ‘b’ 2017-03-06 21:13:35 +01:00
Quique Fdez Guerra
229cdcf6a5 merge configs 2017-03-06 19:34:31 +01:00
Quique Fdez Guerra
95ce3b9e36 Init sass configuration #52 2017-03-06 18:45:23 +01:00
103 changed files with 26051 additions and 5127 deletions

View File

@@ -1,3 +1,11 @@
{
"presets": ["es2015"]
"presets": [
["es2015", {"modules": false}]
],
"env": {
"test": {
"plugins": ["transform-es2015-modules-commonjs"]
}
}
}

View File

@@ -1,11 +1,15 @@
{
"env": {
"jest/globals": true,
"browser": true
},
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
},
"plugins": [
"jest"
],
"rules": {
"no-cond-assign": 0,
"no-console": 2,
@@ -106,6 +110,7 @@
"space-before-blocks": 2,
"space-before-function-paren": [2, "never"],
"spaced-comment": [2, "always"],
"space-in-parens": [2, "never"],
// ECMAScript 6
// http://eslint.org/docs/rules/#ecmascript-6
@@ -128,5 +133,3 @@
"yield-star-spacing": [2, "after"]
}
}

3
.gitignore vendored
View File

@@ -5,6 +5,8 @@
# Third Party #
###############
node_modules/
coverage
.eslintcache
# OS generated files #
######################
@@ -15,3 +17,4 @@ node_modules/
.Trashes
ehthumbs.db
Thumbs.db
webslides.zip

1
.npmignore Normal file
View File

@@ -0,0 +1 @@
.babelrc

95
.sass-lint.yml Normal file
View File

@@ -0,0 +1,95 @@
files:
include: 'src/scss/**/*.scss'
options:
formatter: stylish
merge-default-rules: false
rules:
# Extends
extends-before-mixins: 2
extends-before-declarations: 2
placeholder-in-extend: 2
# Mixins
mixins-before-declarations: 2
# Line Spacing
one-declaration-per-line: 2
empty-line-between-blocks: 2
single-line-per-selector: 2
# Disallows
no-attribute-selectors: 0
no-color-hex: 0
no-color-keywords: 2
no-color-literals: 2
no-combinators: 0
no-debug: 2
no-disallowed-properties: 0
no-duplicate-properties: 2
no-empty-rulesets: 2
no-extends: 0
no-ids: 0
no-important: 2
no-invalid-hex: 2
no-mergeable-selectors: 2
no-misspelled-properties: 2
no-qualifying-elements: 0
no-trailing-whitespace: 2
no-trailing-zero: 2
no-transition-all: 0
no-universal-selectors: 0
no-url-domains: 0
no-url-protocols: 0
no-vendor-prefixes: 2
no-warn: 2
property-units: 0
# Nesting
declarations-before-nesting: 2
force-attribute-nesting: 0
force-element-nesting: 0
force-pseudo-nesting: 0
# Name Formats
class-name-format: 0
function-name-format: 2
id-name-format: 0
mixin-name-format: 2
placeholder-name-format: 2
variable-name-format: 2
# Style Guide
attribute-quotes: 2
bem-depth: 0
border-zero: 2
brace-style: 2
clean-import-paths: 2
empty-args: 2
hex-length: 2
hex-notation: 2
indentation: 2
leading-zero: 2
max-line-length: 0
max-file-line-count: 0
nesting-depth: 2
property-sort-order: 2
pseudo-element: 0
quotes: 2
shorthand-values: 2
url-quotes: 2
variable-for-property: 0
zero-unit: 2
# Inner Spacing
space-after-comma: 2
space-before-colon: 2
space-after-colon: 2
space-before-brace: 2
space-before-bang: 2
space-after-bang: 2
space-between-parens: 2
space-around-operator: 2
# Final Items
trailing-semicolon: 2
final-newline: 2

3
.travis.yml Normal file
View File

@@ -0,0 +1,3 @@
language: node_js
node_js:
- "10"

View File

@@ -1,3 +1,33 @@
# 1.5.0 (2017-09-16)
- [[#96]((https://github.com/webslides/webslides/issues/96))] Using Shift Space now allows to go to previous slide.
- [[#97]((https://github.com/webslides/webslides/issues/97))] Fixing CTRL/CMD + F not allowing to search.
- Dependencies updated.
# 1.4.2 (2017-09-12)
- Fixed `.toc` class. (Regression from Sass)
- Fixed baseline being incorrectly included.
# 1.4.1 (2017-08-18)
- Fixed longform alignments. (Regression from Sass)
- Updated demos to use correct reference.
- Added new unsplash to [demo](http://webslides.tv/demos/keynote).
# 1.4.0 (2017-08-14)
## Misc
- [[#52]((https://github.com/webslides/webslides/issues/52))] We've moved to Sass! We've migrated all of our content to sass so you can customise it a bit more easily.
Tests! We've added tests with the awesome Jest and Travis to keep it tested.
## New features
- [[#73]((https://github.com/webslides/webslides/issues/73))] Slides Index. Press - or click on our slide count to access a fancy new index to quickly navigate to a new slide. Press + or esc to exit or click on one slide to navigate to the slide. You can also disable this feature entirely with an option. Read more
- [[#84]((https://github.com/webslides/webslides/issues/84))] Full Screen Mode. Pressing F now toggles full screen mode to remove all the distractions from the browser. Thanks solilokiam!
- [[#66]((https://github.com/webslides/webslides/issues/66))] New option to disable scroll to navigate.
# 1.3.0 (2017-04-20)
## Misc

View File

@@ -2,19 +2,36 @@
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](http://opensource.org/licenses/MIT)
[![Release](https://img.shields.io/github/release/webslides/webslides.svg)](https://github.com/webslides/webslides/releases/latest)
[![codecov](https://codecov.io/gh/webslides/WebSlides/branch/master/graph/badge.svg)](https://codecov.io/gh/webslides/WebSlides)
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/jlantunez/8)
[![Twitter](https://img.shields.io/twitter/url/https/github.com/webslides/webslides.svg?style=social)](https://twitter.com/webslides)
Finally, everything you need to make HTML presentations, landings, and longforms in a beautiful way. Just the essentials. A new release (at least) every 8th day of the month — [https://webslides.tv/demos](https://webslides.tv/demos).
Finally, everything you need to make HTML presentations, landings, and longforms in a beautiful way. Just a basic knowledge of HTML and CSS is required. Designers, marketers, and journalists can now focus on the content. — [https://webslides.tv/demos](https://webslides.tv/demos).
* * *
### Download
Simply choose a demo and customize it in minutes. Latest version: [webslides.tv/webslides-latest.zip](https://webslides.tv/webslides-latest.zip).
Simply choose a demo and customize it in seconds. Latest version: [webslides.tv/webslides-latest.zip](https://webslides.tv/webslides-latest.zip).
* * *
### Why WebSlides? Productivity
This is about telling the story, and sharing it in a beautiful way. Just a basic knowledge of HTML and CSS is required. Designers, marketers, and journalists can now focus on the content.
### What's in the download?
The download includes demos and images (devices and logos).
All content is for demo purposes only. Images are property of their respective owners.
```
webslides/
├── index.html
├── css/
│ ├── base.css
│ └── colors.css
│ └── svg-icons.css (optional)
├── js/
│ ├── webslides.js
│ └── svg-icons.js (optional)
└── demos/
└── images/
```
## Features
@@ -54,25 +71,6 @@ This is about telling the story, and sharing it in a beautiful way. Just a basic
<article id="webslides" class="vertical">
```
### What's in the download?
The download includes demos and images (devices and logos).
All content is for demo purposes only. Images are property of their respective owners.
```
webslides/
├── index.html
├── css/
│ ├── base.css
│ └── colors.css
│ └── svg-icons.css (optional)
├── js/
│ ├── webslides.js
│ └── svg-icons.js (optional)
└── demos/
└── images/
```
### CSS Syntax (classes)
- Typography: `.text-landing`, `.text-data`, `.text-intro`...
@@ -91,11 +89,10 @@ You can add:
- [Animate on scroll](http://michalsnik.github.io/aos/) (Useful for longform articles)
- [pt](http://williamngan.github.io/pt/)
### Dive In!
- Do not miss [our demos](https://webslides.tv/).
- Want to get techie? Read [our wiki](wiki):
- Want to get techie? Read [our wiki](https://github.com/webslides/WebSlides/wiki):
- [FAQ](https://github.com/webslides/WebSlides/wiki)
- [Core API](https://github.com/webslides/WebSlides/wiki/Core-API)
- [Plugin Docs](https://github.com/webslides/WebSlides/wiki/Plugin-docs)

View File

@@ -25,10 +25,7 @@
<link href="https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,700,700i%7CMaitree:200,300,400,600,700&amp;subset=latin-ext" rel="stylesheet">
<!-- CSS Base -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/base.css">
<!-- CSS Colors -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/colors.css">
<link rel="stylesheet" type='text/css' media='all' href="../static/css/webslides.css">
<!-- Optional - CSS SVG Icons (Font Awesome) -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/svg-icons.css">
@@ -1934,11 +1931,11 @@
<!-- Required -->
<script src="../static/js/webslides.js"></script>
<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>

View File

@@ -25,10 +25,7 @@
<link href="https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,700,700i%7CMaitree:200,300,400,600,700&amp;subset=latin-ext" rel="stylesheet">
<!-- CSS Base -->
<link rel="stylesheet" type='text/css' media='all' href="../static/css/base.css">
<!-- CSS Colors -->
<link rel="stylesheet" type='text/css' media='all' href="../static/css/colors.css">
<link rel="stylesheet" type='text/css' media='all' href="../static/css/webslides.css">
<!-- Optional - CSS SVG Icons (Font Awesome) -->
<link rel="stylesheet" type='text/css' media='all' href="../static/css/svg-icons.css">
@@ -2903,7 +2900,7 @@
<li><strong class="text-label" title="Website">Website:</strong> <a href="http://www.visitasevilla.es/en">visitasevilla.es</a></li>
</ul>
<p>
There are many reasons to visit Seville. Its Old Town contains three UNESCO World Heritage Sites: the Alcázar palace complex, the Cathedral and the General Archive of the Indies.
There are many reasons to visit Seville. Its Old Town contains three UNESCO World Heritage Sites: the Alcázar palace complex, the Cathedral and the General Archive of the Indies.
</p>
</div>
<!-- end .flex-content-->
@@ -3139,7 +3136,7 @@
<!-- Required -->
<script src="../static/js/webslides.js"></script>
<script>
window.ws = new WebSlides();
</script>

View File

@@ -26,10 +26,7 @@
<link href="https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,700,700i%7CMaitree:200,300,400,600,700&amp;subset=latin-ext" rel="stylesheet">
<!-- CSS Base -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/base.css">
<!-- CSS Colors -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/colors.css">
<link rel="stylesheet" type='text/css' media='all' href="../static/css/webslides.css">
<!-- Optional - CSS SVG Icons (Font Awesome) -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/svg-icons.css">

View File

@@ -3,76 +3,73 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CLEAN MARKUP = GOOD KARMA.
Hi source code lover,
you're a curious person and a fast learner ;)
Let's make something beautiful together. Contribute on Github:
https://github.com/webslides/webslides
Thanks!
-->
<!-- SEO -->
<title>WebSlides Demo: Longform Interviews</title>
<meta name="description" content="WebSlides is about telling stories. Create longform interviews with ease.">
<!-- URL CANONICAL -->
<!-- <link rel="canonical" href="http://your-url.com/permalink"> -->
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,700,700i%7CMaitree:200,300,400,600,700&amp;subset=latin-ext" rel="stylesheet">
<!-- CSS Base -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/base.css">
<!-- CSS Colors -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/colors.css">
<link rel="stylesheet" type='text/css' media='all' href="../static/css/webslides.css">
<!-- Optional - CSS SVG Icons (Font Awesome) -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/svg-icons.css">
<!-- SOCIAL CARDS (ADD YOUR INFO) -->
<!-- FACEBOOK -->
<meta property="og:url" content="http://your-url.com/permalink">
<!-- EDIT -->
<meta property="og:type" content="article">
<meta property="og:title" content="WebSlides Demo: Longform Interviews" />
<!-- EDIT -->
<meta property="og:description" content="Create longform interviews with ease. Just the essentials.">
<!-- EDIT -->
<meta property="og:updated_time" content="2017-03-28T12:17:24">
<!-- EDIT -->
<meta property="og:image" content="../static/images/share-webslides.jpg" >
<!-- EDIT -->
<meta property="og:image:width" content="800">
<meta property="og:image:height" content="429">
<!-- TWITTER -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@webslides">
<!-- EDIT -->
<meta name="twitter:creator" content="@jlantunez">
<!-- EDIT -->
<meta name="twitter:title" content="WebSlides Demo: Longform Interviews">
<!-- EDIT -->
<meta name="twitter:description" content="Create longform interviews with ease. Just the essentials.">
<!-- EDIT -->
<meta name="twitter:image" content="../static/images/share-webslides.jpg">
<!-- EDIT -->
<!-- FAVICONS -->
<link rel="shortcut icon" sizes="16x16" href="../static/images/favicons/favicon.png">
<link rel="shortcut icon" sizes="32x32" href="../static/images/favicons/favicon-32.png">
@@ -81,11 +78,11 @@
<link rel="apple-touch-icon icon" sizes="152x152" href="../static/images/favicons/favicon-152.png">
<link rel="apple-touch-icon icon" sizes="180x180" href="../static/images/favicons/favicon-180.png">
<link rel="apple-touch-icon icon" sizes="192x192" href="../static/images/favicons/favicon-192.png">
<!-- Android -->
<meta name="mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#333333">
</head>
<body>
<header role="banner">
@@ -112,10 +109,10 @@
</ul>
</nav>
</header>
<main role="main">
<article>
<section class="bg-black">
<!-- Overlay/Opacity: [class*="bg-"] > .background.dark or .light -->
<span class="background" style="background-image:url('https://source.unsplash.com/E695OZJiju4/1600x800')"></span>
@@ -283,11 +280,11 @@
</div>
<!-- .end .wrap -->
</section>
</article>
</main>
<!--main-->
<footer role="contentinfo">
<div class="wrap">
<div class="grid">
@@ -353,9 +350,9 @@
</div>
<!-- .end .wrap -->
</footer>
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
<script defer src="../static/js/svg-icons.js"></script>
</body>
</html>
</html>

View File

@@ -25,10 +25,7 @@
<link href="https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,700,700i%7CMaitree:200,300,400,600,700&amp;subset=latin-ext" rel="stylesheet">
<!-- CSS Base -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/base.css">
<!-- CSS Colors -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/colors.css">
<link rel="stylesheet" type='text/css' media='all' href="../static/css/webslides.css">
<!-- Optional - CSS SVG Icons (Font Awesome) -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/svg-icons.css">
@@ -727,7 +724,7 @@
<!-- .end .wrap -->
</section>
<section class="bg-black aligncenter">
<span class="background light" style="background-image:url('https://source.unsplash.com/bopC0sTGu-E/')"></span>
<span class="background light" style="background-image:url('https://source.unsplash.com/UxtIESWxLh8/')"></span>
<div class="wrap">
<h2>Embedding Media</h2>
</div>
@@ -838,9 +835,9 @@
<!-- .end .wrap -->
</section>
<section class="bg-apple aligncenter">
<h2><strong>Thank you!</strong></h2>
<h2 class="text-emoji zoomIn">😎</h2>
<h3><strong>Thank you!</strong></h2>
<p><a href="https://twitter.com/webslides" title="@WebSlides on Twitter">@WebSlides</a></p>
<p class="text-symbols">* * *</p>
</section>
</article>
@@ -849,7 +846,7 @@
<!-- Required -->
<script src="../static/js/webslides.js"></script>
<script>
window.ws = new WebSlides();
</script>

View File

@@ -25,10 +25,7 @@
<link href="https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,700,700i%7CMaitree:200,300,400,600,700&amp;subset=latin-ext" rel="stylesheet">
<!-- CSS Base -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/base.css">
<!-- CSS Colors -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/colors.css">
<link rel="stylesheet" type='text/css' media='all' href="../static/css/webslides.css">
<!-- Optional - CSS SVG Icons (Font Awesome) -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/svg-icons.css">
@@ -1924,13 +1921,13 @@
<!-- Required -->
<script src="../static/js/webslides.js"></script>
<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>

View File

@@ -3,76 +3,73 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CLEAN MARKUP = GOOD KARMA.
Hi source code lover,
you're a curious person and a fast learner ;)
Let's make something beautiful together. Contribute on Github:
https://github.com/webslides/webslides
Thanks!
-->
<!-- SEO -->
<title>WebSlides Demo: Longforms</title>
<meta name="description" content="WebSlides is about telling stories. Create longform articles with ease.">
<!-- URL CANONICAL -->
<!-- <link rel="canonical" href="http://your-url.com/permalink"> -->
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,700,700i%7CMaitree:200,300,400,600,700&amp;subset=latin-ext" rel="stylesheet">
<!-- CSS Base -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/base.css">
<!-- CSS Colors -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/colors.css">
<link rel="stylesheet" type='text/css' media='all' href="../static/css/webslides.css">
<!-- Optional - CSS SVG Icons (Font Awesome) -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/svg-icons.css">
<!-- SOCIAL CARDS (ADD YOUR INFO) -->
<!-- FACEBOOK -->
<meta property="og:url" content="https://webslides.tv/demos/why-webslides">
<!-- EDIT -->
<meta property="og:type" content="article">
<meta property="og:title" content="WebSlides Demo: Longforms" />
<!-- EDIT -->
<meta property="og:description" content="Create longform articles with ease. Just the essentials.">
<!-- EDIT -->
<meta property="og:updated_time" content="2017-03-28T18:24:48">
<!-- EDIT -->
<meta property="og:image" content="../static/images/share-webslides.jpg" >
<!-- EDIT -->
<meta property="og:image:width" content="800">
<meta property="og:image:height" content="429">
<!-- TWITTER -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@webslides">
<!-- EDIT -->
<meta name="twitter:creator" content="@jlantunez">
<!-- EDIT -->
<meta name="twitter:title" content="WebSlides Demo: Longforms">
<!-- EDIT -->
<meta name="twitter:description" content="Create longform articles with ease. Just the essentials.">
<!-- EDIT -->
<meta name="twitter:image" content="../static/images/share-webslides.jpg">
<!-- EDIT -->
<!-- FAVICONS -->
<link rel="shortcut icon" sizes="16x16" href="../static/images/favicons/favicon.png">
<link rel="shortcut icon" sizes="32x32" href="../static/images/favicons/favicon-32.png">
@@ -81,11 +78,11 @@
<link rel="apple-touch-icon icon" sizes="152x152" href="../static/images/favicons/favicon-152.png">
<link rel="apple-touch-icon icon" sizes="180x180" href="../static/images/favicons/favicon-180.png">
<link rel="apple-touch-icon icon" sizes="192x192" href="../static/images/favicons/favicon-192.png">
<!-- Android -->
<meta name="mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#333333">
</head>
<body>
<header role="banner">
@@ -340,11 +337,11 @@
</div>
<!-- .end .wrap -->
</section>
</article>
</main>
<!--main-->
<footer role="contentinfo">
<div class="wrap">
<div class="grid">
@@ -410,9 +407,9 @@
</div>
<!-- .end .wrap -->
</footer>
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
<script defer src="../static/js/svg-icons.js"></script>
</body>
</html>
</html>

View File

@@ -3,72 +3,69 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CLEAN MARKUP = GOOD KARMA.
Hi source code lover,
you're a curious person and a fast learner ;)
Let's make something beautiful together. Contribute on Github:
https://github.com/webslides/webslides
Thanks!
-->
<!-- SEO -->
<title>WebSlides Tutorial: Videos, Images, and Maps</title>
<meta name="description" content="How to embed images, videos, and maps in your presentation.">
<!-- URL CANONICAL -->
<!-- <link rel="canonical" href="http://your-url.com/permalink"> -->
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,700,700i%7CMaitree:200,300,400,600,700&amp;subset=latin-ext" rel="stylesheet">
<!-- CSS Base -->
<link rel="stylesheet" type='text/css' media='all' href="../static/css/base.css">
<!-- CSS Colors -->
<link rel="stylesheet" type='text/css' media='all' href="../static/css/colors.css">
<link rel="stylesheet" type='text/css' media='all' href="../static/css/webslides.css">
<!-- Optional - CSS SVG Icons (Font Awesome) -->
<link rel="stylesheet" type='text/css' media='all' href="../static/css/svg-icons.css">
<!-- SOCIAL CARDS (ADD YOUR INFO) -->
<!-- FACEBOOK -->
<meta property="og:url" content="/" />
<meta property="og:type" content="article" />
<meta property="og:title" content="WebSlides Tutorial: Media" />
<!-- EDIT -->
<meta property="og:description" content="How to embed images, videos, and maps in your presentation.">
<!-- EDIT -->
<meta property="og:updated_time" content="2017-01-04T17:25:31">
<!-- EDIT -->
<meta property="og:image" content="../static/images/share-webslides.jpg" >
<!-- EDIT -->
<!-- TWITTER -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@webslides">
<!-- EDIT -->
<meta name="twitter:creator" content="@jlantunez">
<!-- EDIT -->
<meta name="twitter:title" content="WebSlides Tutorial: Media">
<!-- EDIT -->
<meta name="twitter:description" content="How to embed images, videos, and maps in your presentation.">
<!-- EDIT -->
<meta name="twitter:image" content="../static/images/share-webslides.jpg">
<!-- EDIT -->
<!-- FAVICONS -->
<link rel="shortcut icon" sizes="16x16" href="../static/images/favicons/favicon.png">
<link rel="shortcut icon" sizes="32x32" href="../static/images/favicons/favicon-32.png">
@@ -77,11 +74,11 @@
<link rel="apple-touch-icon icon" sizes="152x152" href="../static/images/favicons/favicon-152.png">
<link rel="apple-touch-icon icon" sizes="180x180" href="../static/images/favicons/favicon-180.png">
<link rel="apple-touch-icon icon" sizes="192x192" href="../static/images/favicons/favicon-192.png">
<!-- Android -->
<meta name="mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#333333">
</head>
<body>
<header role="banner">
@@ -108,16 +105,16 @@
</ul>
</nav>
</header>
<main role="main">
<article id="webslides">
<!-- Quick Guide
- Each parent <section> in the <article id="webslides"> element is an individual slide.
- Vertical sliding = <article id="webslides" class="vertical">
- <div class="wrap"> = container 90% / <div class="wrap size-50"> = 45%;
-->
<section class="bg-black-blue aligncenter">
<span class="background dark" style="background-image:url('https://source.unsplash.com/Zq_K89I9E-8/)"></span>
<!--.wrap = container (width: 90%) -->
@@ -192,7 +189,6 @@
<!-- .end .wrap -->
</section>
<section>
<span class="background-bottom" style="background-image:url('https://source.unsplash.com/GQD3Av_9A88/1600x800)"></span>
<div class="wrap aligncenter">
<h3>
<svg class="fa-camera">
@@ -724,7 +720,7 @@
<div class="grid">
<div class="column">
<pre>&lt;div class="embed"&gt;
<strong>&lt;div data-youtube data-youtube-id=&quot;CQY3KUR3VzM&quot; data-autoplay data-loop&gt;
<strong>&lt;div data-youtube data-youtube-id=&quot;CQY3KUR3VzM&quot; data-autoplay data-loop&gt;
&lt;/div&gt;</strong>
&lt;/div&gt;</pre>
<p>autoplay + loop</p>
@@ -732,7 +728,7 @@
<!-- .end .column -->
<div class="column">
<pre>&lt;div class="embed"&gt;
<strong>&lt;div data-youtube data-youtube-id=&quot;CQY3KUR3VzM&quot; data-autoplay data-mute data-no-controls&gt;
<strong>&lt;div data-youtube data-youtube-id=&quot;CQY3KUR3VzM&quot; data-autoplay data-mute data-no-controls&gt;
&lt;/div&gt;</strong>
&lt;/div&gt;</pre>
<p>autoplay + mute + no controls.</p>
@@ -749,7 +745,7 @@
<h3>YouTube API</h3>
<p><code>autoplay + loop</code></p>
<pre>&lt;div class="embed"&gt;
&lt;div data-youtube data-youtube-id=&quot;_m67JbGjWnc&quot; <strong>data-autoplay data-loop</strong>&gt;
&lt;div data-youtube data-youtube-id=&quot;_m67JbGjWnc&quot; <strong>data-autoplay data-loop</strong>&gt;
&lt;/div&gt;
&lt;/div&gt;</pre>
</div>
@@ -876,7 +872,7 @@
<li><strong class="text-label" title="Website">Website:</strong> <a href="http://www.visitasevilla.es/en">visitasevilla.es</a></li>
</ul>
<p>
There are many reasons to visit Seville. Its Old Town contains three UNESCO World Heritage Sites: the Alcazar palace complex, the Cathedral and the General Archive of the Indies.
There are many reasons to visit Seville. Its Old Town contains three UNESCO World Heritage Sites: the Alcazar palace complex, the Cathedral and the General Archive of the Indies.
</p>
</div>
<!-- end .flex-content-->
@@ -887,7 +883,7 @@
</section>
<section class="fullscreen">
<div class="embed">
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3170.254536199183!2d-5.994303837186783!3d37.38381233311839!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0%3A0xbaa976bfaec1fe87!2sReal+Alc%C3%A1zar+de+Sevilla!5e0!3m2!1ses!2ses!4v1489408674667" width="800" height="600" allowfullscreen></iframe>
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3170.254536199183!2d-5.994303837186783!3d37.38381233311839!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0%3A0xbaa976bfaec1fe87!2sReal+Alc%C3%A1zar+de+Sevilla!5e0!3m2!1ses!2ses!4v1489408674667" width="800" height="600" allowfullscreen></iframe>
</div>
<!-- .end .embed -->
</section>
@@ -932,20 +928,20 @@
<h2 class="text-emoji zoomIn"><strong><a href="https://webslides.tv" title="WebSlides">😎</a></strong></h2>
<h3><a href="https://twitter.com/webslides" title="WebSlides on Twitter">@WebSlides</a></h3>
</section>
</article>
</main>
<!--main-->
<!-- Required -->
<script src="../static/js/webslides.js"></script>
<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>
</html>

View File

@@ -3,47 +3,44 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CLEAN MARKUP = GOOD KARMA.
Hi source code lover,
you're a curious person and a fast learner ;)
Let's make something beautiful together. Contribute on Github:
https://github.com/webslides/webslides
Thanks!
-->
<!-- SEO -->
<title>Netflix's Culture &middot; WebSlides</title>
<meta name="description" content="Patty McCord wrote the document called 'Netflix Culture: Freedom & Responsibility'.It's one of the most important documents ever to come out of Silicon Valley.">
<!-- URL CANONICAL -->
<!-- <link rel="canonical" href="http://your-url.com/permalink"> -->
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,700,700i%7CMaitree:200,300,400,600,700&amp;subset=latin-ext" rel="stylesheet">
<!-- CSS Base -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/base.css">
<!-- CSS Colors -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/colors.css">
<link rel="stylesheet" type='text/css' media='all' href="../static/css/webslides.css">
<!-- Optional - CSS SVG Icons (Font Awesome) -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/svg-icons.css">
<!-- SOCIAL CARDS (ADD YOUR INFO) -->
<!-- FACEBOOK -->
<!-- EDIT -->
<meta property="og:url" content="http://your-url.com/permalink">
<!-- EDIT -->
<meta property="og:type" content="article">
<meta property="og:title" content="WebSlides: Netflix's Culture" />
<meta property="og:description" content="Patty McCord created Netflix's culture. This is a homage.">
<!-- EDIT -->
<meta property="og:updated_time" content="2017-04-16T16:24:56">
<!-- EDIT -->
@@ -51,11 +48,11 @@
<!-- EDIT -->
<meta property="og:image:width" content="800">
<meta property="og:image:height" content="429">
<!-- TWITTER -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@webslides">
<!-- EDIT -->
<meta name="twitter:creator" content="@jlantunez">
<!-- EDIT -->
@@ -64,9 +61,9 @@
<meta name="twitter:description" content="Patty McCord created Netflix's culture. This is a homage.">
<!-- EDIT -->
<meta name="twitter:image" content="../static/images/share-webslides.jpg">
<!-- EDIT -->
<!-- FAVICONS -->
<link rel="shortcut icon" sizes="16x16" href="../static/images/favicons/favicon.png">
<link rel="shortcut icon" sizes="32x32" href="../static/images/favicons/favicon-32.png">
@@ -75,16 +72,16 @@
<link rel="apple-touch-icon icon" sizes="152x152" href="../static/images/favicons/favicon-152.png">
<link rel="apple-touch-icon icon" sizes="180x180" href="../static/images/favicons/favicon-180.png">
<link rel="apple-touch-icon icon" sizes="192x192" href="../static/images/favicons/favicon-192.png">
<!-- Android -->
<meta name="mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#333333">
</head>
<body>
<header role="banner">
<nav role="navigation">
<p class="logo"><a href="https://webslides.tv" title="WebSlides">WebSlides</a></p>
<p class="logo"><a href="../index.html" title="WebSlides">WebSlides</a></p>
<ul>
<li class="github">
<a rel="external" href="https://github.com/webslides/webslides" title="Github">
@@ -106,16 +103,16 @@
</ul>
</nav>
</header>
<main role="main">
<article id="webslides">
<!-- Quick Guide
- Each parent <section> in the <article id="webslides"> element is an individual slide.
- Vertical sliding = <article id="webslides" class="vertical">
- <div class="wrap"> = container 90% / <div class="wrap size-50"> = 45%;
-->
<section class="bg-red">
<span class="background dark" style="background-image:url('https://source.unsplash.com/R1J6Z1cnJZc/1600x800')"></span>
<!--.wrap = container (width: 90%) -->
@@ -365,11 +362,11 @@
</div>
<!-- .end .wrap -->
</section>
</article>
</main>
<!--main-->
<footer>
<div class="wrap">
<p>
@@ -377,15 +374,15 @@
</p>
</div>
</footer>
<!-- Required -->
<script src="../static/js/webslides.js"></script>
<script>
window.ws = new WebSlides();
</script> <!-- Autoslide? window.ws = new WebSlides({ autoslide: 8000 }); -->
<!-- OPTIONAL - svg-icons.js (fontastic.me - Font Awesome as svg icons) -->
<script defer src="../static/js/svg-icons.js"></script>
</body>
</html>
</html>

View File

@@ -25,10 +25,7 @@
<link href="https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,700,700i%7CMaitree:200,300,400,600,700&amp;subset=latin-ext" rel="stylesheet">
<!-- CSS Base -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/base.css">
<!-- CSS Colors -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/colors.css">
<link rel="stylesheet" type='text/css' media='all' href="../static/css/webslides.css">
<!-- Optional - CSS SVG Icons (Font Awesome) -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/svg-icons.css">
@@ -1865,7 +1862,7 @@
<!-- Required -->
<script src="../static/js/webslides.js"></script>
<script>
window.ws = new WebSlides();
</script>

View File

@@ -25,10 +25,7 @@
<link href="https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,700,700i%7CMaitree:200,300,400,600,700&amp;subset=latin-ext" rel="stylesheet">
<!-- CSS Base -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/base.css">
<!-- CSS Colors -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/colors.css">
<link rel="stylesheet" type='text/css' media='all' href="../static/css/webslides.css">
<!-- Optional - CSS SVG Icons (Font Awesome) -->
<link rel="stylesheet" type="text/css" media="all" href="../static/css/svg-icons.css">
@@ -69,7 +66,7 @@
<body>
<header role="banner">
<nav role="navigation">
<p class="logo"><a href="https://webslides.tv" title="WebSlides">WebSlides</a></p>
<p class="logo"><a href="../index.html" title="WebSlides">WebSlides</a></p>
<ul>
<li class="github">
<a rel="external" href="https://github.com/webslides/webslides" title="Github">
@@ -341,7 +338,7 @@
<!-- Required -->
<script src="../static/js/webslides.js"></script>
<!-- Autoslide 5 seconds. If you don't want autoslide, remove: {autoslide: 5000} -->
<script>
window.ws = new WebSlides({ autoslide: 5000 });

View File

@@ -25,11 +25,8 @@
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,700,700i%7CMaitree:200,300,400,600,700&amp;subset=latin-ext" rel="stylesheet">
<!-- CSS Base -->
<link rel="stylesheet" type='text/css' media='all' href="static/css/base.css">
<!-- CSS Colors -->
<link rel="stylesheet" type='text/css' media='all' href="static/css/colors.css">
<!-- CSS WebSlides -->
<link rel="stylesheet" type='text/css' media='all' href="static/css/webslides.css">
<!-- Optional - CSS SVG Icons (Font Awesome) -->
<link rel="stylesheet" type='text/css' media='all' href="static/css/svg-icons.css">
@@ -297,11 +294,11 @@
</svg>
<strong>Guides</strong>
</h4>
<p>If you need help, here's just three tutorials. Just a basic knowledge of HTML is required:</p>
<p>If you need help, here's just some tutorials. Just a basic knowledge of HTML is required:</p>
<ul class="description">
<li><a href="demos/components.html" title="WebSlides Components">WebSlides Components</a>.</li>
<li><a href="demos/classes.html" title="WebSlides Classes">WebSlides Classes</a>.</li>
<li><a href="demos/media.html" title="WebSlides Media">WebSlides Media: images, videos...</a></li>
<li><a href="/demos/components.html" title="WebSlides Components">Components</a> &middot; <a href="/demos/classes.html" title="WebSlides Classes">Classes</a>.</li>
<li><a href="https://codepen.io/webslides" title="WebSlides on Codepen">WebSlides on Codepen</a>.</li>
<li><a href="/demos/media.html" title="WebSlides Media">WebSlides Media: images, videos...</a></li>
</ul>
</div>
<div class="column">
@@ -360,7 +357,7 @@
</svg>
</a>
</h2>
<p>People share content that makes them feel inspired. WebSlides is a very effective way to engage young audiences, customers, and teams.</p>
<p>People share content that makes them feel inspired. WebSlides is a very effective way to engage young audiences, customers, and teams.</p>
<p>Best,<br> <a href="https://twitter.com/jlantunez">@jlantunez</a>, <a href="https://twitter.com/belelros">@belelros</a>, and <a href="https://twitter.com/luissacristan">@luissacristan</a>.</p>
</div>
<!-- .end .content-right -->

14398
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "webslides",
"version": "1.3.2",
"version": "1.5.0",
"description": "Making HTML presentations easy",
"main": "static/js/webslides.js",
"repository": {
@@ -19,7 +19,7 @@
},
{
"name": "Antonio Laguna",
"email": "a.laguna@funcion13.com"
"email": "anlagmat@gmail.com"
}
],
"license": "MIT",
@@ -28,53 +28,65 @@
},
"homepage": "https://github.com/webslides/webslides#readme",
"devDependencies": {
"ava": "^0.19.1",
"babel-cli": "^6.24.1",
"babel-core": "^6.24.1",
"babel-loader": "^6.4.1",
"babel-preset-env": "^1.4.0",
"archiver": "^2.0.3",
"autoprefixer": "^7.1.4",
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
"babel-jest": "^22.0.4",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"browser-env": "^2.0.30",
"eslint": "^3.19.0",
"eslint-loader": "^1.7.1",
"npm-run-all": "^4.0.2",
"rimraf": "^2.6.1",
"codecov": "^3.0.0",
"css-loader": "^0.28.7",
"eslint": "^4.7.0",
"eslint-loader": "^1.9.0",
"eslint-plugin-jest": "^21.1.0",
"extract-text-webpack-plugin": "^3.0.0",
"jest": "^22.0.4",
"node-sass": "4.13.1",
"npm-run-all": "^4.1.1",
"postcss-loader": "^2.0.6",
"pre-commit": "^1.2.2",
"rimraf": "^2.6.2",
"sass-lint": "^1.11.1",
"sass-loader": "^6.0.6",
"simulant": "^0.2.2",
"smart-banner-webpack-plugin": "^3.0.1",
"webpack": "^2.4.1",
"webpack-dev-server": "^2.4.2"
"style-loader": "^0.19.1",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.8.2"
},
"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",
"build": "npm-run-all -s lint build:*",
"build:min": "webpack --output-filename [name].min.js -p",
"build:normal": "webpack",
"lint": "npm-run-all -p lint:*",
"lint:js": "eslint ./src/js --cache --ignore-pattern .gitignore",
"lint:tests": "eslint ./test --cache --ignore-pattern .gitignore",
"lint:css": "sass-lint -v -f stylish",
"dev": "webpack-dev-server",
"test": "ava test/*.js"
"test": "jest && codecov",
"preversion": "npm jest",
"postversion": "npm run build && git add -A static && node ./zip-release.js && git push && git push --tags"
},
"babel": {
"presets": [
[
"es2015",
{
"modules": false
},
"@ava/stage-4",
"@ava/transform-test-files"
]
"release": {
"files": [
"demos/**/**",
"static/**/**",
"*.html",
"LICENSE",
"README.md"
]
},
"ava": {
"babel": {
"presets": [
"es2015",
"stage-0",
"react"
]
},
"require": [
"babel-register",
"./test/helpers/setup-browser-env.js"
]
"jest": {
"collectCoverage": true,
"testURL": "http://localhost/"
},
"pre-commit": [
"lint"
],
"dependencies": {
"request": "^2.83.0"
}
}

7
postcss.config.js Normal file
View File

@@ -0,0 +1,7 @@
module.exports = {
plugins: [
require('autoprefixer')({
browsers: ['last 2 versions'],
})
]
};

View File

@@ -1,3 +1,4 @@
import WebSlides from './modules/webslides';
require('../scss/full.scss');
window.WebSlides = WebSlides;

View File

@@ -8,8 +8,9 @@ const CLASSES = {
const Events = {
ENTER: 'dom:enter',
LEAVE: 'dom:leave',
DISABLE: 'slide:disable',
ENABLE: 'slide:enable',
DISABLE: 'slide:disable'
SHOW: 'slide:show'
};
/**
@@ -36,7 +37,7 @@ class Slide {
*/
this.i = i;
this.el.id = `section-${(i + 1)}`;
this.el.id = this.el.id ? this.el.id : `section-${(i + 1)}`;
this.el.classList.add(CLASSES.SLIDE);
// Hide slides by default
@@ -57,6 +58,7 @@ class Slide {
show() {
DOM.show(this.el);
this.el.classList.add(CLASSES.CURRENT);
this.fire_(Events.SHOW);
}
/**

View File

@@ -5,7 +5,8 @@ import scrollTo from '../utils/scroll-to';
const CLASSES = {
VERTICAL: 'vertical',
READY: 'ws-ready'
READY: 'ws-ready',
DISABLED: 'disabled'
};
// Default plugins
@@ -19,7 +20,8 @@ const PLUGINS = {
'scroll': Plugins.Scroll,
'touch': Plugins.Touch,
'video': Plugins.Video,
'youtube': Plugins.YouTube
'youtube': Plugins.YouTube,
'zoom': Plugins.Zoom
};
@@ -36,18 +38,23 @@ export default class WebSlides {
* @param {boolean} loop Whether to go to first slide from last one or not.
* @param {number} minWheelDelta Controls the amount of needed scroll to
* trigger navigation.
* @param {boolean} navigateOnScroll Whether scroll can trigger navigation or
* not.
* @param {number} scrollWait Controls the amount of time to wait till
* navigation can occur again with scroll.
* @param {number} slideOffset Controls the amount of needed touch delta to
* trigger navigation.
* @param {boolean} showIndex Controls if the index can be shown.
*/
constructor({
autoslide = false,
changeOnClick = false,
loop = true,
minWheelDelta = 40,
navigateOnScroll = true,
scrollWait = 450,
slideOffset = 50
slideOffset = 50,
showIndex = true
} = {}) {
/**
* WebSlide element.
@@ -106,8 +113,10 @@ export default class WebSlides {
changeOnClick,
loop,
minWheelDelta,
navigateOnScroll,
scrollWait,
slideOffset
slideOffset,
showIndex
};
/**
* Initialisation flag.
@@ -352,7 +361,7 @@ export default class WebSlides {
* @private
*/
isValidIndexSlide_(i) {
return i >= 0 && i < this.maxSlide_;
return typeof i === 'number' && i >= 0 && i < this.maxSlide_;
}
/**
@@ -373,6 +382,7 @@ export default class WebSlides {
// Keeping the order
if (slideNumber !== 0) {
let i = 0;
while(i < slideNumber) {
this.slides[i].moveAfterLast();
i++;
@@ -382,6 +392,75 @@ export default class WebSlides {
this.goToSlide(slideNumber);
}
/**
* Toggles zoom
*/
toggleZoom() {
if (this.options.showIndex) {
this.plugins.zoom.toggleZoom();
}
}
/**
* Disables the webslides element adding a class "disabled"
*/
disable() {
this.el.classList.add(CLASSES.DISABLED);
if (this.plugins.autoslide &&
this.plugins.autoslide.time !== false) {
this.plugins.autoslide.stop();
}
}
/**
* Enables the webslides element removing a class "disabled"
*/
enable() {
this.el.classList.remove(CLASSES.DISABLED);
if (this.plugins.autoslide &&
this.plugins.autoslide.time !== false) {
this.plugins.autoslide.play();
}
}
/**
* Checks if it is disabled
* @return {boolean}
*/
isDisabled() {
return this.el.classList.contains(CLASSES.DISABLED);
}
/**
* Puts the browser into fullscreen
*/
fullscreen() {
const el = document.documentElement;
const isFullscreen = document.fullscreen
|| document.webkitIsFullScreen
|| document.mozFullScreen
|| document.msFullScreenElement;
if (!isFullscreen) {
/* istanbul ignore next hard to test prefixes */
const requestFullscreen = el.requestFullscreen
|| el.webkitRequestFullScreen
|| el.mozRequestFullScreen
|| el.msRequestFullscreen;
requestFullscreen.call(el);
} else {
/* istanbul ignore next hard to test prefixes */
const cancelFullscreen = document.exitFullScreen
|| document.webkitCancelFullScreen
|| document.mozCancelFullScreen
|| document.msExitFullscreen;
cancelFullscreen.call(document);
}
}
/**
* Registers a plugin to be loaded when the instance is created. It allows
* (on purpose) to replace default plugins.

View File

@@ -29,15 +29,21 @@ export default class Keyboard {
let method;
let argument;
if (DOM.isFocusableElement()) {
if (DOM.isFocusableElement() || this.ws_.isDisabled()) {
return;
}
switch (event.which) {
case Keys.AV_PAGE:
case Keys.SPACE:
method = this.ws_.goNext;
break;
case Keys.SPACE:
if (event.shiftKey) {
method = this.ws_.goPrev;
} else {
method = this.ws_.goNext;
}
break;
case Keys.RE_PAGE:
method = this.ws_.goPrev;
break;
@@ -60,11 +66,19 @@ export default class Keyboard {
break;
case Keys.RIGHT:
method = !this.ws_.isVertical ? this.ws_.goNext : null;
break;
case Keys.F:
if (!event.metaKey && ! event.ctrlKey) {
method = this.ws_.fullscreen;
}
break;
}
if (method) {
method.call(this.ws_, argument);
// Prevents Firefox key events.
event.preventDefault();
}
}
}

View File

@@ -48,7 +48,7 @@ export default class Navigation {
* Counter Element.
* @type {Element}
*/
this.counter = DOM.createNode('span', ELEMENT_ID.COUNTER);
this.counter = Navigation.createCounter(ELEMENT_ID.COUNTER, wsInstance);
/**
* @type {WebSlides}
* @private
@@ -60,6 +60,9 @@ export default class Navigation {
this.el.appendChild(this.counter);
this.ws_.el.appendChild(this.el);
this.slides = Array.prototype.slice.call(
document.querySelectorAll('#webslides section')).map(s => s.id);
this.bindEvents_();
}
@@ -72,6 +75,30 @@ export default class Navigation {
'ws:slide-change', this.onSlideChanged_.bind(this));
this.next.addEventListener('click', this.onButtonClicked_.bind(this));
this.prev.addEventListener('click', this.onButtonClicked_.bind(this));
this.counter.addEventListener('click', this.onButtonClicked_.bind(this));
document.body.addEventListener('click', this.onBodyClicked_.bind(this));
}
/**
* Whenever the body is clicked, check if the element has [data-slide] attr
* and if so, navigate to it.
* @param {MouseEvent} event Click event
*/
onBodyClicked_(event) {
const matches = document.body.matches || document.body.msMatchesSelector;
let el;
if (matches.call(event.target, '[data-slide]')) {
el = event.target;
} else if (matches.call(event.target, '[data-slide] *')) {
el = event.target.querySelector('[data-slide]');
}
if (el) {
event.preventDefault();
const i = this.slides.indexOf(el.dataset.slide);
this.ws_.goToSlide(i);
}
}
/**
@@ -80,7 +107,11 @@ export default class Navigation {
* @param {string|number} max Max slide number.
*/
updateCounter(current, max) {
this.counter.textContent = `${current} / ${max}`;
if (this.ws_.options.showIndex) {
this.counter.childNodes[0].textContent = `${current} / ${max}`;
} else {
this.counter.textContent = `${current} / ${max}`;
}
}
/**
@@ -97,6 +128,24 @@ export default class Navigation {
return arrow;
}
/**
* Creates the navigation counter.
* @param {!String} id Desired ID for the counter.
* @param {WebSlides} ws_ WebSlides object.
* @return {Element} The arrow element.
*/
static createCounter(id, ws_) {
const counter = DOM.createNode('span', id);
if (ws_.options.showIndex) {
const link = document.createElement('a');
link.href = '#';
link.title = 'View all slides';
counter.appendChild(link);
}
return counter;
}
/**
* Slide Change event handler. Will update the text on the navigation.
* @param {CustomEvent} event
@@ -115,8 +164,10 @@ export default class Navigation {
event.preventDefault();
if (event.target === this.next) {
this.ws_.goNext();
} else {
} else if (event.target === this.prev) {
this.ws_.goPrev();
} else {
this.ws_.toggleZoom();
}
}
}

View File

@@ -8,6 +8,7 @@ import Scroll from './scroll';
import Touch from './touch';
import Video from './video';
import YouTube from './youtube';
import Zoom from './zoom';
export default {
AutoSlide,
@@ -19,5 +20,6 @@ export default {
Scroll,
Touch,
Video,
YouTube
YouTube,
Zoom
};

View File

@@ -40,6 +40,11 @@ export default class Scroll {
*/
this.timeout_ = null;
// Disabling from option
if (!this.ws_.options.navigateOnScroll) {
return;
}
if (!MobileDetector.isAny()) {
this.scrollContainer_.addEventListener(
'wheel', this.onMouseWheel_.bind(this));
@@ -71,11 +76,17 @@ export default class Scroll {
* @private
*/
onMouseWheel_(event) {
if (this.ws_.isDisabled()) {
return;
}
if (this.ws_.isMoving || this.timeout_) {
event.preventDefault();
return;
}
// Firefox uses lines instead of pixels for delta
const linesToPx = event.deltaMode * this.ws_.options.minWheelDelta;
const {deltaY: wheelDeltaY, deltaX: wheelDeltaX} = event;
const isVertical = this.ws_.isVertical;
const isHorizontalMovement = Math.abs(wheelDeltaX) > Math.abs(wheelDeltaY);
@@ -94,8 +105,8 @@ export default class Scroll {
}
}
if (Math.abs(wheelDeltaY) >= this.ws_.options.minWheelDelta ||
Math.abs(wheelDeltaX) >= this.ws_.options.minWheelDelta) {
if (Math.abs(wheelDeltaY + linesToPx) >= this.ws_.options.minWheelDelta ||
Math.abs(wheelDeltaX + linesToPx) >= this.ws_.options.minWheelDelta) {
if ((isHorizontalMovement && this.isGoingLeft_) ||
(!isHorizontalMovement && this.isGoingUp_)) {
this.ws_.goPrev();

View File

@@ -63,6 +63,27 @@ export default class Touch {
*/
this.isEnabled = false;
/**
* Whether is a gesture or not.
* @type {boolean}
* @private
*/
this.isGesture = false;
/**
* Stores start touch event (x, y).
* @type {array}
* @private
*/
this.startTouches = [];
/**
* Stores end touch event (x, y).
* @type {array}
* @private
*/
this.endTouches = [];
let events;
if (MobileDetector.isAny()) {
@@ -87,12 +108,22 @@ export default class Touch {
* @private
*/
onStart_(event) {
if (this.ws_.isDisabled()) {
return;
}
const info = Touch.normalizeEventInfo(event);
this.startX_ = info.x;
this.startY_ = info.y;
this.endX_ = info.x;
this.endY_ = info.y;
if (event.touches.length === 1) {
this.startX_ = info.x;
this.startY_ = info.y;
this.endX_ = info.x;
this.endY_ = info.y;
} else if (event.touches.length > 1) {
this.startTouches = Touch.getTouchCoordinates(event);
this.endTouches = this.startTouches;
this.isGesture = true;
}
}
/**
@@ -101,10 +132,18 @@ export default class Touch {
* @private
*/
onMove_(event) {
if (this.ws_.isDisabled()) {
return;
}
const info = Touch.normalizeEventInfo(event);
this.endX_ = info.x;
this.endY_ = info.y;
if (this.isGesture) {
this.endTouches = Touch.getTouchCoordinates(event);
} else {
this.endX_ = info.x;
this.endY_ = info.y;
}
}
/**
@@ -112,19 +151,57 @@ export default class Touch {
* @private
*/
onStop_() {
const diffX = this.startX_ - this.endX_;
const diffY = this.startY_ - this.endY_;
if (this.ws_.isDisabled()) {
return;
}
// It's an horizontal drag
if (Math.abs(diffX) > Math.abs(diffY)) {
if (diffX < -this.ws_.options.slideOffset) {
this.ws_.goPrev();
} else if(diffX > this.ws_.options.slideOffset) {
this.ws_.goNext();
if (this.isGesture) {
const startDistance = Math.sqrt(
Math.pow(this.startTouches[0].x - this.startTouches[1].x, 2) +
Math.pow(this.startTouches[0].y - this.startTouches[1].y, 2)
);
const endDistance = Math.sqrt(
Math.pow(this.endTouches[0].x - this.endTouches[1].x, 2) +
Math.pow(this.endTouches[0].y - this.endTouches[1].y, 2)
);
if (startDistance > endDistance) {
// Pinch gesture
this.ws_.toggleZoom();
}
this.isGesture = false;
} else {
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 < -this.ws_.options.slideOffset) {
this.ws_.goPrev();
} else if(diffX > this.ws_.options.slideOffset) {
this.ws_.goNext();
}
}
}
}
/**
* Get X,Y coordinates from touch pointers.
* @param {Event} event
* @return {Object}
*/
static getTouchCoordinates(event) {
return [
{
x: event.touches[0].clientX,
y: event.touches[0].clientY
},
{
x: event.touches[1].clientX,
y: event.touches[1].clientY
}
];
}
/**
* Normalizes an event to deal with differences between PointerEvent and
* TouchEvent.

196
src/js/plugins/zoom.js Normal file
View File

@@ -0,0 +1,196 @@
import DOM from '../utils/dom';
import Keys from '../utils/keys';
import scrollTo from '../utils/scroll-to';
import Slide from '../modules/slide';
const CLASSES = {
ZOOM: 'grid',
DIV: 'column',
WRAP: 'wrap-zoom',
WRAP_CONTAINER: 'wrap',
CURRENT: 'current',
SLIDE: 'slide',
ZOOM_ENABLED: 'ws-ready-zoom'
};
const ID = 'webslides-zoomed';
/**
* Zoom plugin.
*/
export default class Zoom {
/**
* @param {WebSlides} wsInstance The WebSlides instance
* @constructor
*/
constructor(wsInstance) {
/**
* @type {WebSlides}
* @private
*/
this.ws_ = wsInstance;
/**
* @type {WebSlides}
* @private
*/
this.zws_ = {};
/**
* @type {boolean}
* @private
*/
this.isZoomed_ = false;
this.preBuildZoom_();
document.body.addEventListener('keydown', this.onKeyDown.bind(this));
}
/**
* On key down handler. Will decide if Zoom in or out
* @param {Event} event Key down event.
*/
onKeyDown(event) {
if (!this.isZoomed_ && Keys.MINUS.some(key => key === event.which)) {
this.zoomIn();
} else if (this.isZoomed_ &&
(Keys.PLUS.some(key => key === event.which) ||
event.which === Keys.ESCAPE)) {
this.zoomOut();
}
}
/**
* Prepare zoom structure, scales the slides and uses a grid layout
* to show them.
*/
preBuildZoom_() {
// Clone #webslides element
this.zws_.el = this.ws_.el.cloneNode();
this.zws_.el.id = ID;
this.zws_.wrap = DOM.createNode('div');
this.zws_.wrap.className = CLASSES.WRAP_CONTAINER;
this.zws_.el.appendChild(this.zws_.wrap);
this.zws_.grid = DOM.createNode('div');
this.zws_.grid.className = CLASSES.ZOOM;
this.zws_.wrap.appendChild(this.zws_.grid);
this.zws_.el.addEventListener('click', () => this.toggleZoom());
// Clone the slides
this.zws_.slides = [].map.call(this.ws_.slides,
(slide, i) => {
const s_ = slide.el.cloneNode(true);
this.zws_.grid.appendChild(s_);
return new Slide(s_, i);
});
this.disable();
DOM.after(this.zws_.el, this.ws_.el);
// Creates the container for each slide
this.zws_.slides.forEach(elem => this.createSlideBlock_(elem));
}
/**
* Creates a block structure around the slide.
* @param {Element} elem slide element.
*/
createSlideBlock_(elem) {
// Wraps the slide around a container
const wrap = DOM.wrap(elem.el, 'div');
wrap.className = CLASSES.WRAP;
wrap.setAttribute('id', `zoomed-${elem.el.getAttribute('id')}`);
// Slide container, need due to flexbox styles
const div = DOM.wrap(wrap, 'div');
div.className = CLASSES.DIV;
// Adding some layer for controlling click events
const divLayer = DOM.createNode('div');
divLayer.className = 'zoom-layer';
divLayer.addEventListener('click', e => {
e.stopPropagation();
this.zoomOut();
this.ws_.goToSlide(elem.i);
});
wrap.appendChild(divLayer);
// Slide number
const slideNumber = DOM.createNode('p', '', `${elem.i + 1}`);
slideNumber.className = 'text-slide-number';
div.appendChild(slideNumber);
}
/**
* Toggles zoom.
*/
toggleZoom() {
if (this.isZoomed_) {
this.zoomOut();
} else {
this.zoomIn();
}
}
/**
* Zoom In the slider, scales the slides and uses a grid layout to show them.
*/
zoomIn() {
if (!this.ws_.options.showIndex) return;
this.enable();
const currentId = this.ws_.currentSlide_.el.id;
const zoomedCurrent = this.zws_.el
.querySelector(`.${CLASSES.WRAP}.${CLASSES.CURRENT}`);
if (zoomedCurrent) {
zoomedCurrent.classList.remove(CLASSES.CURRENT);
}
const actualCurrent = this.zws_.el
.querySelector(`#zoomed-${currentId}`);
actualCurrent.classList.add(CLASSES.CURRENT);
this.isZoomed_ = true;
document.documentElement.classList.add(CLASSES.ZOOM_ENABLED);
setTimeout(() => {
this.ws_.disable();
this.zws_.el.classList.add('in');
const wrapCSS = window.getComputedStyle(this.zws_.grid);
const scrollingElement = document.body;
scrollTo(actualCurrent.parentNode.offsetTop
+ DOM.parseSize(wrapCSS.paddingTop), 50, () => {}, scrollingElement);
}, 50);
}
/**
* Zoom Out the slider, remove scale from the slides.
*/
zoomOut() {
if (!this.ws_.options.showIndex) return;
this.zws_.el.classList.remove('in');
setTimeout(() => {
this.ws_.enable();
this.disable();
this.isZoomed_ = false;
document.documentElement.classList.remove(CLASSES.ZOOM_ENABLED);
}, 400);
}
/**
* Hides the zoom container
*/
disable() {
this.zws_.el.classList.add('disabled');
}
/**
* Shows the zoom container
*/
enable() {
this.zws_.el.classList.remove('disabled');
}
}

View File

@@ -15,6 +15,7 @@ function canIuseNativeCustom() {
return 't' === p.type && 'b' === p.detail.a;
} catch (e) { }
/* istanbul ignore next: hard to reproduce on test environment */
return false;
}
@@ -25,6 +26,7 @@ function canIuseNativeCustom() {
* @return {Event}
* @constructor
*/
/* istanbul ignore next: hard to reproduce on test environment */
const IECustomEvent = function CustomEvent(type, params) {
const e = document.createEvent('CustomEvent');
@@ -37,6 +39,7 @@ const IECustomEvent = function CustomEvent(type, params) {
return e;
};
/* istanbul ignore next: hard to reproduce on test environment */
const WSCustomEvent = canIuseNativeCustom() ? NativeCustomEvent : IECustomEvent;
export default WSCustomEvent;

View File

@@ -18,7 +18,9 @@ export default class DOM {
*/
static createNode(tag, id = '', text = '') {
const node = document.createElement(tag);
node.id = id;
if (id) {
node.id = id;
}
if (text) {
node.textContent = text;
@@ -46,14 +48,17 @@ export default class DOM {
/**
* Gets the prefixed transitionend event.
* @param {?Element} optEl Element to check
* @return {string}
*/
static getTransitionEvent() {
if (transitionEvent) {
static getTransitionEvent(optEl) {
if (transitionEvent && !optEl) {
return transitionEvent;
}
const el = document.createElement('ws');
transitionEvent = '';
const el = optEl || document.createElement('ws');
const transitions = {
'transition': 'transitionend',
'OTransition': 'oTransitionEnd',
@@ -76,14 +81,17 @@ export default class DOM {
/**
* Gets the prefixed animation end event.
* @param {?Element} optEl Element to check
* @return {string}
*/
static getAnimationEvent() {
if (animationEvent) {
static getAnimationEvent(optEl) {
if (animationEvent && !optEl) {
return animationEvent;
}
const el = document.createElement('ws');
animationEvent = 'animationend';
const el = optEl || document.createElement('ws');
const animations = {
'animation': 'animationend',
'OAnimation': 'oAnimationEnd',
@@ -93,11 +101,12 @@ export default class DOM {
const animationNames = Object.keys(animations);
for (let i = 0, length = animationNames.length;
i < length && !animationEvent; i++) {
i < length; i++) {
const animationName = animationNames[i];
if (typeof el.style[animationName] !== 'undefined') {
animationEvent = animations[animationName];
break;
}
}
@@ -121,6 +130,15 @@ export default class DOM {
el.style.display = '';
}
/**
* Checks if the element is visible.
* @param {Element} el Element to check.
* @return {boolean}
*/
static isVisible(el) {
return (el.offsetParent !== null);
}
/**
* Fires a custom event on the given target.
* @param {Element} target The target of the event.
@@ -130,7 +148,8 @@ export default class DOM {
*/
static fireEvent(target, eventType, eventInfo = {}) {
const event = new WSCustomEvent(eventType, {
detail: eventInfo
detail: eventInfo,
bubbles: true
});
target.dispatchEvent(event);
@@ -155,14 +174,52 @@ export default class DOM {
let result = false;
if (document.activeElement) {
const isContentEditable = document.activeElement
.contentEditable !== 'inherit';
const isContentEditable =
document.activeElement.contentEditable !== 'inherit' &&
document.activeElement.contentEditable !== undefined;
const isInput = ['INPUT', 'SELECT', 'OPTION', 'TEXTAREA']
.indexOf(document.activeElement.tagName) > -1;
result = isInput || isContentEditable;
}
return result;
}
/**
* Gets the integer value of a style property.
* @param {string} prop CSS property value.
* @return {Number} The property without the units.
*/
static parseSize(prop) {
return Number(prop.replace(/[^\d\.]/g, ''));
}
/**
* Wraps a HTML structure around an element.
* @param {Element} elem the element to be wrapped.
* @param {string} tag the new element tag.
* @return {Element} the new element.
*/
static wrap(elem, tag) {
const wrap = document.createElement(tag);
elem.parentElement.insertBefore(wrap, elem);
wrap.appendChild(elem);
return wrap;
}
/**
* Inserts and element after another element.
* @param {Element} elem the element to be inserted.
* @param {Element} target the element to be inserted after.
*/
static after(elem, target) {
const parent = target.parentNode;
if (parent.lastChild === target) {
parent.appendChild(elem);
} else {
parent.insertBefore(elem, target.nextSibling);
}
}
}

View File

@@ -7,13 +7,4 @@ 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};
export default {swing};

View File

@@ -8,7 +8,11 @@ const Keys = {
LEFT: 37,
UP: 38,
RIGHT: 39,
DOWN: 40
DOWN: 40,
PLUS: [107, 171, 187],
MINUS: [109, 173, 189],
ESCAPE: 27,
F: 70
};
export default Keys;

View File

@@ -1,6 +1,6 @@
import Easings from './easing';
const SCROLLABLE_CONTAINER = document.getElementById('webslides');
let SCROLLABLE_CONTAINER = document.getElementById('webslides');
/**
* Smoothly scrolls to a given Y position using Easing.Swing. It'll run a
@@ -8,8 +8,13 @@ const SCROLLABLE_CONTAINER = document.getElementById('webslides');
* @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.
* @param {HTMLElement} container The HTML element where to scroll
*/
export default function scrollTo(y, duration = 500, cb = () => {}) {
export default function scrollTo(
y, duration = 500, cb = () => {}, container = null) {
SCROLLABLE_CONTAINER = container ?
container : document.getElementById('webslides');
const delta = y - SCROLLABLE_CONTAINER.scrollTop;
const startLocation = SCROLLABLE_CONTAINER.scrollTop;
const increment = 16;

198
src/scss/_base.scss Normal file
View File

@@ -0,0 +1,198 @@
// sass-lint:disable no-vendor-prefixes
/*=========================================
1. Base --> Baseline: 8px = .8rem
=========================================== */
/* -- Disable elastic scrolling/bounce:
webslides.js will add .ws-ready automatically. Don't worry :) -- */
.ws-ready {
&,
body {
height: 100%;
overflow: hidden;
width: 100%;
}
&.ws-ready-zoom {
overflow: visible;
body {
overflow: auto;
}
}
}
#webslides {
-ms-overflow-style: none;
-webkit-overflow-scrolling: touch; // sass-lint:disable-line no-misspelled-properties
height: 100vh;
overflow-x: hidden;
overflow-y: scroll;
&::-webkit-scrollbar {
display: none;
}
}
li li {
margin-left: 1.6rem;
}
a,
a:active,
a:focus,
a:visited,
input:focus,
textarea:focus,
button {
text-decoration: none;
transition: all .3s ease-out;
}
p a:active {
position: relative;
top: 2px;
}
nav a[rel='external'] em,
.hidden {
clip: rect(1px, 1px, 1px, 1px);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.shadow {
position: relative;
&:before,
&:after {
bottom: 1.6rem;
content: '';
max-width: 300px;
position: absolute;
top: 80%;
width: 50%;
z-index: -1;
}
&:after {
right: 2.4rem;
transform: rotate(3deg);
}
&:before {
left: 2.4rem;
transform: rotate(-3deg);
}
}
/*=== 1.1 WRAP/CONTAINER === */
.wrap,
header nav,
footer nav {
margin-left: auto;
margin-right: auto;
max-width: 100%;
position: relative;
width: 100%;
z-index: 2;
@media (min-width: 1024px) {
width: 90%;
}
}
.frame,
.shadow {
padding: 2.4rem;
}
.radius {
border-radius: .4rem;
}
.alignright {
float: right;
}
.alignleft {
float: left;
}
.aligncenter {
margin-left: auto;
margin-right: auto;
text-align: center;
}
img.aligncenter,
figure.aligncenter {
display: block;
margin-bottom: .8rem;
margin-top: .8rem;
}
img.alignleft,
figure.alignleft,
img.alignright,
figure.alignright,
img.aligncenter,
figure.aligncenter {
margin-bottom: 3.2rem;
margin-top: 3.2rem;
}
img.alignright,
svg.alignright,
figure.alignright {
margin: .8rem 0 .8rem 2.4rem;
}
img.alignleft,
svg.alignleft,
figure.alignleft {
margin: .8rem 2.4rem .8rem 0;
}
$sizes: 80, 70, 60, 50, 40, 30, 20;
/*=== div.size-60, img.size-50, h1.size-40, p.size-30... === */
@media (min-width: 1024px) {
@each $size in $sizes {
.size-#{$size} {
width: $size * 1%;
}
}
}
pre,
code {
font-family: 'Cousine', monospace;
}
pre {
font-size: 1.6rem;
line-height: 2.4rem;
overflow: auto;
padding: 2.4rem;
text-align: left;
white-space: pre-wrap;
width: 100%;
word-wrap: break-word;
& + p {
margin-top: 3.2rem;
}
code {
padding: 0;
}
}
code {
padding: .4rem;
}

817
src/scss/_color.scss Normal file
View File

@@ -0,0 +1,817 @@
// sass-lint:disable no-color-literals
// sass-lint:disable no-vendor-prefixes
/*=========================================
19. Colors
=========================================== */
/* -- Disable elastic scrolling/bounce:
webslides.js will add .ws-ready automatically. Don't worry :) -- */
body {
background-color: $body-bg;
color: $body-color;
}
:focus {
box-shadow: $focus-box-shadow;
}
svg {
fill: currentColor;
}
[class*='bg-'] a,
[class*='bg-gradient-'] a {
color: $spindle;
}
.bg-brown a {
color: $link-color-secondary;
}
a,
.bg-white a,
.bg-light a,
.bg-gradient-white a {
color: $link-color;
}
a:hover {
color: $link-hover;
}
.flexblock li>a,
[class*='bg-'] li>a,
[class*='bg-gradient-'] li>a,
article header a {
color: inherit;
}
hr {
background: $hr-bg;
}
hr:after {
background-color: rgba($white, .8);
color: $body-color;
}
abbr,
acronym {
border-bottom: 1px dotted $body-bg;
}
mark,
ins {
background-color: rgba($pattens-blue, .8);
color: inherit;
}
::-moz-selection {
background-color: rgba($pattens-blue, .8);
}
::-webkit-selection {
background-color: rgba($pattens-blue, .8);
}
::selection {
background-color: rgba($pattens-blue, .8);
}
pre {
background: $white;
border: 1px solid rgba($stratos, .1);
box-shadow: 0 8px 16px rgba($stratos, .04), 0 4px 16px rgba($black, .08);
}
pre:hover {
box-shadow: 0 8px 16px rgba(0, 40, 160, .08), 0 8px 24px rgba($black, .08);
}
code,
[class*='bg-'] pre {
background-color: rgba($white, .09);
}
.bg-white code {
background: rgba($stratos, .03);
}
/*================================================
Slides - Backgrounds <section class="bg-primary">
================================================== */
/*3 Corp Colors*/
@each $name, $color in $bg-colors {
.bg-#{$name} {
background-color: $color;
}
}
[class*='bg-'] .bg-white {
color: $body-color;
text-shadow: none;
}
/* BG Apple Keynote*/
.bg-apple {
background: linear-gradient(to bottom, $black 0%, #1a2028 50%, #293845 100%);
}
/*Font Color*/
.bg-trans-dark,
.bg-trans-gradient,
.bg-primary,
.bg-secondary,
.bg-blue,
.bg-green,
.bg-purple,
.bg-red,
.bg-facebook,
.bg-apple,
[class*='bg-black'],
[class*='bg-gradient-'] {
color: $white;
text-shadow: 0 1px 0 #013;
}
.bg-light p {
color: #456;
}
.bg-brown p {
color: #666;
}
/*Transparent/Opacity*/
.bg-trans-dark {
background: rgba($black, .8);
}
.bg-trans-light {
background: rgba($black, .2);
}
/*Covers/Longforms...*/
.bg-trans-gradient {
background: linear-gradient(to top, rgba($black, .8) 0%, rgba($black, 0) 100%);
}
/*Horizontal Gradient*/
.bg-gradient-h {
background: linear-gradient(134deg, #32b 0, #62b 100%);
}
/*Vertical Gradient*/
.bg-gradient-v {
background: linear-gradient(to top, #62b 0%, #32b 100%);
}
/*Radial Gradient*/
.bg-gradient-r {
background: radial-gradient(ellipse at center, #62b 0%, #32b 100%);
}
/*White Gradient (vertical)*/
.bg-gradient-white {
background: linear-gradient(180deg, #f2f4f6 0, $white 100%);
color: $body-color;
text-shadow: none;
}
/*Gray Gradient (horizontal)*/
.bg-gradient-gray {
background: linear-gradient(90deg, #f7f9fb 0, #dee2e6 100%);
color: $body-color;
text-shadow: none;
}
/*Border/Frame*/
.frame {
border: .8rem solid $white;
}
[class*='background'].frame {
border-width: .2rem;
}
/*Layer/Box Shadow*/
.shadow,
.pre {
position: relative;
}
.shadow:before,
.shadow:after {
box-shadow: 0 16px 24px rgba($stratos, .3);
}
/*============================
TYPOGRAPHY
============================== */
/* -- Horizontal separator -- */
.text-separator:before {
background-color: rgba(170, 0, 0, .8);
}
/* -- Pull Quote (Right/Left) -- */
[class*='text-pull-'] {
border-top: 4px solid rgba($black, .5);
}
img[class*='text-pull-'],
figure[class*='text-pull-'] {
border-top: 0;
}
/* -- Context -- */
[class*='bg-'] .text-context:before {
background-color: $white;
}
.text-context:before,
.bg-white .text-context:before {
background-color: rgba($stratos, .2);
}
/* -- Text shadow -- */
.text-shadow {
text-shadow: 0 0 40px rgba($black, .5);
}
/* -- time, ampersands, prepositions (for, of...), symbols...
[class*='card-'] time,
h1 span {
color: #abd;
}
/* -- <pre> comment -- */
.code-comment {
color: rgba(70, 170, 130, .9);
text-shadow: none;
}
/*=========================================
Header/Nav
=========================================== */
header[role='banner'] {
background-color: $white;
}
.logo a {
color: inherit;
}
nav[role='navigation'] li {
&.active a {
background-color: #555;
color: $white;
}
a {
background-color: rgba(50, 50, 50, .9);
color: $white;
&:hover {
background-color: rgba(50, 50, 50, .7);
}
}
}
@each $name, $color in $social-nav {
nav li.#{$name} a:hover {
background-color: $color;
}
}
/*===================================================
.flexblock li hover/active
===================================================== */
.flexblock li.active a,
.metrics li:hover,
.specs li:hover,
.reasons li:hover {
background-color: rgba($stratos, .03);
}
/*=========================================
Features & Clients List
=========================================== */
.features li,
.clients li {
background-color: rgba($white, .9);
}
[class*='bg-'] .features li,
[class*='bg-'] .clients li {
background-color: rgba($white, .1);
}
.features li:hover,
.clients li:hover {
box-shadow: 0 8px 16px rgba($stratos, .02), 0 4px 16px rgba($black, .08);
}
/*============================
.flexblock with border
============================== */
.border {
border-bottom: 1px solid rgba($stratos, .1);
border-right: 1px solid rgba($stratos, .1);
}
.border li {
border-left: 1px solid rgba($stratos, .1);
border-top: 1px solid rgba($stratos, .1);
}
.flexblock.border li li {
border: 0;
}
/*===========================================
flexblock.steps
============================================= */
.steps li:nth-child(1) {
background-color: #e8eef7;
}
.steps li:nth-child(2) {
background-color: #dde5f3;
}
.steps li:nth-child(3) {
background-color: #cdd8ec;
}
.steps li:nth-child(4) {
background-color: #bbcdec;
}
.process {
border-bottom: 15px solid transparent;
border-top: 15px solid transparent;
}
.steps li:hover,
.steps.blink li:hover>a {
background-color: #b8cef7;
}
@media (min-width: 1024px) {
.process.step-2 {
border-left-color: #e8eef7;
}
.process.step-3 {
border-left-color: #dde5f3;
}
.process.step-4 {
border-left-color: #cdd8ec;
}
.steps li:hover + li [class*='step-'] {
border-left-color: #b8cef7;
}
}
/*=========================================================
Items: You can use for settings, drag&drop, close/delete...
=========================================================== */
.specs li:after {
background: linear-gradient(to right, rgba($stratos, 0) 0%, rgba($stratos, .2) 50%, rgba($stratos, 0) 100%);
}
.specs li:last-child:after {
background: none;
}
/*=========================================================
Why/Steps/Motivation/Reasons - Decimal/Numbers
=========================================================== */
.reasons li:after {
background: linear-gradient(to right, rgba($stratos, 0) 0%, rgba($stratos, .2) 50%, rgba($stratos, 0) 100%);
}
.reasons li:last-child:after {
background: none;
}
/*=========================================
Overlays
=========================================== */
.overlay {
background-color: rgba($black, .2);
}
li:hover .overlay {
background-color: rgba($black, .1);
}
.overlay,
.overlay a {
color: $white;
text-shadow: 0 1px 0 #111;
}
/*=========================================
Gallery li+.overlay+image
=========================================== */
.gallery li {
background-color: rgba($stratos, .06);
box-shadow: 0 1px 1px rgba($black, .2), 0 4px 8px rgba($black, .03);
}
.gallery li figcaption {
background-color: $white;
}
.flexblock.gallery li:hover {
box-shadow: 0 1px 1px rgba($black, .2), 0 4px 8px rgba($black, .08);
}
.gallery li footer {
border-top: 1px solid rgba($stratos, .1);
}
.gallery li a {
color: $body-color;
text-shadow: none;
}
.flesblock.gallery li a footer {
color: #aaa;
}
/*Arrow */
.gallery li figcaption:before {
border: .8rem solid $black;
border-color: transparent transparent $white $white;
}
/*=========================================
Plans / Pricing
=========================================== */
.plans>li div,
.flexblock.plans li:hover div {
background-color: $white;
}
.plans>li:hover,
.plans>li:nth-child(2) {
box-shadow: 0 1px 1px rgba($black, .1), 0 8px 16px rgba($black, .1);
}
.plans:hover li:nth-child(2):not(:hover) {
box-shadow: none;
}
.plans li h2 {
background-color: rgba($stratos, .5);
color: $white;
}
.plans ul li {
border-bottom: 1px solid rgba($stratos, .1);
&:last-child {
border-bottom: 0;
}
}
.plans > li > a {
color: $body-color;
text-shadow: none;
}
/*============================
Activity/CV/Timeline/News
============================== */
.activity li {
border-top: .1rem solid rgba($stratos, .1);
}
.activity li:hover {
background-color: rgba($stratos, .02);
}
/*=========================================
Resume/Work/CV/Portfolio
=========================================== */
.work-label,
.work li a {
border-bottom: 1px solid rgba($stratos, .1);
}
.work li:nth-child(odd)>a {
background-color: rgba($stratos, .03);
}
.work li a:hover {
background-color: rgba($stratos, .04);
}
/*===========================================
Clients / Services / Logos...
============================================= */
.clients.border figcaption {
border-top: 1px solid rgba($stratos, .1);
}
/*====================
LOGOS
====================== */
/* --- Images (black logo/image) --- */
img.blacklogo {
background: none;
filter: grayscale(100%) brightness(10%) contrast(100%);
}
/* --- Images (gray logo/image) --- */
img.graylogo {
filter: grayscale(100%) brightness(10%) contrast(10%);
}
/* --- Images (white Logo/Image) --- */
img.whitelogo {
filter: brightness(0) invert(1);
}
/* --- Logo/Images Hover --- */
li:hover img.blacklogo,
li:hover img.graylogo,
img.blacklogo:hover,
img.graylogo:hover {
background: none;
filter: grayscale(0%);
transition: all .6s ease;
}
/*=========================================================
Cards
=========================================================== */
[class*='card-'] > a {
color: inherit;
}
/* --- card ul specs --- */
.description>li {
border-bottom: 1px solid rgba($stratos, .1);
}
.description>li:last-child {
border-bottom: 0;
}
/*== Figure Background === */
[class*='card-'][class*='bg-'] figure {
background-color: rgba($stratos, .06);
}
/*== Ficaption Cards === */
[class*='card'] figcaption,
[class*='card'] figcaption a {
background: linear-gradient(to bottom, rgba($black, 0) 0%, rgba($black, .2) 100%);
color: $white;
}
/*===CTA (Call to Action - Numbers, Price, Promo...) ===== */
@media (min-width: 768px) {
.cta .benefit {
border-image: linear-gradient(90deg, transparent, rgba($black, .4) 50%, transparent) 1 100%;
border-left-width: 1px;
border-style: solid;
}
}
/*=========================================
Tables
=========================================== */
table td,
th,
thead {
border: 1px solid rgba($black, .5);
}
thead {
background-color: rgba($black, .3);
}
tr:nth-child(even)>td {
background: rgba($black, .1);
}
tr>td {
border-top: 1px solid rgba($black, .5);
}
td:hover,
tr:nth-child(even)>td:hover {
background-color: rgba($white, .5);
}
/*============================
Browser (Screenshots)
============================== */
.browser {
border: 1px solid rgba($stratos, .1);
}
.browser:hover {
box-shadow: 0 1px 1px rgba($black, .1), 0 8px 16px rgba($black, .1);
}
/*=== Topbar === */
.browser:before {
background-color: rgba($stratos, .1);
border-bottom: 1px solid rgba($stratos, .2);
color: rgba($white, .9);
}
.browser:hover:before {
background-color: rgba($stratos, .12);
color: $white;
}
/*=========================================
Forms
=========================================== */
input,
textarea {
background-color: #fafbfc;
}
input:focus,
textarea:focus {
background-color: $white;
box-shadow: 0 0 5px rgba(81, 203, 238, 1);
}
input:focus::-moz-placeholder {
color: #ddd;
}
input:focus::-webkit-input-placeholder {
color: #ddd;
}
a.button,
[class*='badge-'],
button[type='submit'],
input {
box-shadow: 0 10px 16px -8px rgba($stratos, .3);
}
button,
input,
select,
textarea,
button[type='submit'],
input[type='submit'],
.button,
.button:hover,
button[type='submit']:hover,
input[type='submit']:hover {
border: 1px solid $royal-blue;
}
button[type='submit'],
input[type='submit'],
.button,
.button:hover,
button[type='submit']:hover,
input[type='submit']:hover {
background-color: $royal-blue;
color: $white;
text-shadow: 0 1px 0 #123;
}
.button:active,
button[type='submit']:active,
input[type='submit']:active {
background-color: #17d;
}
.ghost,
.ghost:hover {
background: none;
color: inherit;
text-shadow: none;
}
.bg-primary select,
.bg-primary textarea,
.bg-primary .button,
.bg-primary button,
.bg-primary button:hover,
.bg-primary input,
[class*='bg-gradient-'] .button,
[class*='bg-'] a.button.ghost {
border-color: $white;
}
[class*='bg-'] a.button {
color: $white;
}
.bg-white a.button.ghost,
.bg-gradient-white a.button.ghost {
border: 1px solid $royal-blue;
color: $body-color;
}
:disabled,
button:disabled:hover {
background-color: #eee;
border-color: #eee;
color: #ccc;
}
fieldset {
background-color: rgba($stratos, .2);
border: 1px solid $royal-blue;
}
legend {
background-color: rgba($black, .6);
color: $white;
}
/* Inputs/Buttons - hover */
input:hover,
select:hover {
box-shadow: 0 0 8px rgba($black, .3);
}
/* App Store Badges */
[class*='badge-'] {
background-color: $black;
border: 1px solid #345;
}
form .flexblock li:hover {
background-color: rgba($black, .05);
}
/*============================
Table of Contents
============================== */
.toc,
.toc ol>li:before,
.chapter {
background-color: #f7f9fb;
}
.toc li .toc-page:before {
border-bottom: 1px dotted rgba($black, .9);
}
/*============================
Slides (Counter/Arrows)
============================== */
#counter,
#navigation a {
color: #abc;
}
#webslides:hover #navigation a:hover {
background-color: $index-overlay;
color: $white;
}
/*============================
Footer
============================== */
footer[role='contentinfo'] {
background-color: $white;
}
/*============================
Slides Index
============================== */
#webslides-zoomed {
background: $index-overlay;
}
#webslides-zoomed .column > .wrap-zoom {
background-color: $catskill-white;
box-shadow: 0 1px 1px rgba(0, 0, 0, .2), 0 4px 8px rgba(0, 0, 0, .04);
color: $mine-shaft;
&:hover {
box-shadow: 0 1px 1px rgba(0, 0, 0, .2), 0 4px 8px rgba(0, 0, 0, .08);
}
&.current {
border: .6rem solid rgba(0, 20, 280, .2);
}
}
.text-slide-number {
color: #abc;
}

468
src/scss/_typography.scss Normal file
View File

@@ -0,0 +1,468 @@
/*============================
2. TYPOGRAPHY & LISTS
============================== */
html,
body {
font-weight: 300;
line-height: 1;
text-rendering: optimizeLegibility;
}
html,
body,
input,
select,
textarea {
font-family: 'Roboto', 'San Francisco', helvetica, arial, sans-serif;
font-size: 62.5%;
}
body,
textarea {
font-size: 1.8rem;
}
p,
li,
dt,
dd,
time,
table,
big,
textarea,
label {
line-height: 3.2rem;
margin-bottom: 3.2rem;
}
li,
p:last-child {
margin-bottom: 0;
}
ul>li,
ol>li {
margin-left: 3.2rem;
}
li li {
font-size: 100%;
}
/*== List .description (Product/Specs) === */
ul.description {
padding: 0;
& + p {
margin-top: 3.2rem;
}
li {
padding-bottom: .8rem;
padding-top: .8rem;
position: relative;
transition: .3s;
}
li:hover {
padding-left: .4rem;
}
}
ul.description li,
.column ul li {
list-style: none;
margin-left: 0;
}
.column ol>li {
margin-left: 1.6rem;
}
h1 svg,
h2 svg,
h3 svg,
h4 svg {
margin-top: -.8rem;
}
.text-intro svg,
.text-quote p svg,
.wall p svg,
.try svg {
margin-top: -.4rem;
}
h1 {
font-size: 4rem;
line-height: 5.6rem;
@media (min-width: 768px) {
font-size: 5.6rem;
line-height: 7.2rem;
}
}
h1 span {
font-style: italic;
}
h2 {
font-size: 3.2rem;
line-height: 4.8rem;
@media (min-width: 768px) {
font-size: 4.8rem;
line-height: 6.4rem;
}
}
h3 {
font-size: 2.4rem;
line-height: 4rem;
@media (min-width: 768px) {
font-size: 4rem;
line-height: 5.6rem;
}
}
h4 {
font-size: 2.2rem;
line-height: 4rem;
@media (min-width: 768px) {
font-size: 3.2rem;
line-height: 4.8rem;
}
}
h5 {
font-size: 2rem;
font-weight: 600;
line-height: 3.2rem;
}
h6 {
font-size: 1.8rem;
font-weight: 600;
line-height: 3.2rem;
}
h2.alignleft + p.alignright {
margin-bottom: 0;
margin-top: 1.2rem;
}
h3.alignleft + p.alignright {
margin-bottom: 0;
margin-top: .4rem;
}
@for $i from 1 through 6 {
@for $j from 1 through 6 {
h#{$i}+h#{$j} {
margin-top: .8rem;
}
}
}
h1+img,
h2+img,
h3+img {
margin-bottom: 4.8rem;
margin-top: 4.8rem;
}
[class*='content-'] > [class*='content-'] h2,
[class*='content-'] > [class*='content-'] h3,
[class*='content-'] > [class*='content-'] h4 {
font-size: 2.4rem;
line-height: 4rem;
}
/*== 2.1. Headings with background ==*/
@for $i from 1 through 6 {
h#{$i}[class*='bg-'] {
padding: 2.4rem;
}
}
ul[class*='bg-'],
ol[class*='bg-'],
li[class*='bg-'],
p[class*='bg-'] {
padding: 2.4rem;
}
h1 [class*='bg-'],
h2 [class*='bg-'],
h3 [class*='bg-'] {
padding: .4rem .8rem;
}
/*== 2.2. Typography Classes = .text- == */
.text-intro,
[class*='content-'] p {
font-size: 2.4rem;
line-height: 4rem;
}
/* -- Serif -- */
.text-serif,
h1 span {
font-family: 'Maitree', times, serif;
}
/* -- h1,h2... Promo/Landings -- */
.text-landing {
letter-spacing: .4rem;
text-transform: uppercase;
@media (min-width: 768px) {
letter-spacing: 1.6rem;
}
}
/* -- Subtitle (Before h1, h2) p.subtitle + h1/h2 */
.text-subtitle {
letter-spacing: .2rem;
margin-bottom: 0;
text-transform: uppercase;
p#{&} {
font-size: 1.6rem;
svg {
vertical-align: text-top;
}
}
+ p {
margin-top: 3.2rem;
}
}
.text-uppercase {
text-transform: uppercase;
}
.text-lowercase {
text-transform: lowercase;
}
/* -- Emoji (you'll love this) -- */
.text-emoji {
font-size: 6.8rem;
line-height: 8.8rem;
@media (min-width: 768px) {
font-size: 12.8rem;
line-height: 16rem;
}
}
/* -- Numbers (results, sales... 23,478,289 iphones) -- */
.text-data {
font-size: 6.4rem;
line-height: 8rem;
margin-bottom: .8rem;
@media (min-width: 768px) {
font-size: 15.2rem;
line-height: 16.8rem;
}
}
.text-label {
display: inline-block;
font-weight: 600;
text-transform: uppercase;
width: 12.8rem;
}
/* -- Magazine Two Columns -- */
@media (min-width: 768px) {
.text-cols {
column-count: 2;
column-gap: 4.8rem;
text-align: left;
}
.text-landing + .text-cols {
margin-top: 3.2rem;
}
}
.text-cols p:first-child:first-letter {
float: left;
font-size: 11rem;
font-weight: 600;
line-height: 1;
margin: -.4rem 1.6rem 0 0;
padding: 0;
text-transform: uppercase;
}
/* -- Heading with border -- */
.text-context {
position: relative;
&:before {
content: '';
display: block;
height: .2rem;
margin-bottom: .6rem;
width: 12rem;
.column & {
width: 100%;
}
}
&.text-uppercase {
letter-spacing: .1rem;
}
}
/* -- Separator/Symbols (stars ***...) -- */
.text-symbols {
font-weight: 600;
letter-spacing: .8rem;
text-align: center;
}
.text-separator {
margin-top: 2.4rem;
&:before {
content: '';
height: .4rem;
left: 0;
margin-top: -1.6rem;
position: absolute;
width: 16%;
}
@media (min-width: 568px) {
margin-left: 20%;
margin-top: 0;
width: 80%;
&:before {
margin-top: 1.2rem;
}
}
}
/* -- Pull Quote (Right/Left) -- */
[class*='text-pull'] {
font-size: 2.4rem;
font-weight: 400;
line-height: 4rem;
margin-bottom: 3.2rem;
margin-left: 2.4rem;
margin-right: 2.4rem;
position: relative;
}
[class*='text-pull-'] {
margin-top: .8rem;
padding-top: 1.4rem;
@media (min-width: 1024px) {
margin-left: -4.8rem;
margin-right: -4.8rem;
}
}
@media (min-width: 568px) {
[class*='text-pull-'] {
max-width: 40%;
}
.text-pull-right {
float: right;
margin-left: 2.4rem;
margin-right: -2.4rem;
}
.text-pull-left {
float: left;
margin-left: -2.4rem;
margin-right: 2.4rem;
}
}
img[class*='text-pull-'],
figure[class*='text-pull-'] {
margin-top: .8rem;
padding-top: 0;
}
/* -- Interviews (Questions & Answers) --- */
/* -- <dl class="text-interview">
<dt>name</dt>
<dd><p>question or answer</p>
</dd>
--- */
.text-interview dt {
font-weight: 600;
margin-bottom: 0;
text-transform: uppercase;
}
@media (min-width: 1024px) {
.text-interview dt {
margin-left: -34%;
position: absolute;
text-align: right;
white-space: nowrap;
width: 30%;
}
}
/* -- Info Messages (error, warning, success... -- */
.text-info {
font-size: 1.6rem;
line-height: 2.4rem;
}
/*=========================================
2.1. San Francisco Font (Apple's new font)
=========================================== */
.text-apple,
.bg-apple {
font-family: 'San Francisco', helvetica, arial, sans-serif;
}
/* Ultra Light */
@font-face {
font-family: 'San Francisco';
font-weight: 100;
src: url('https://applesocial.s3.amazonaws.com/assets/styles/fonts/sanfrancisco/sanfranciscodisplay-ultralight-webfont.woff2');
}
/* Thin */
@font-face {
font-family: 'San Francisco';
font-weight: 200;
src: url('https://applesocial.s3.amazonaws.com/assets/styles/fonts/sanfrancisco/sanfranciscodisplay-thin-webfont.woff2');
}
/* Regular */
@font-face {
font-family: 'San Francisco';
font-weight: 400;
src: url('https://applesocial.s3.amazonaws.com/assets/styles/fonts/sanfrancisco/sanfranciscodisplay-regular-webfont.woff2');
}
/* Bold */
@font-face {
font-family: 'San Francisco';
font-weight: bold;
src: url('https://applesocial.s3.amazonaws.com/assets/styles/fonts/sanfrancisco/sanfranciscodisplay-bold-webfont.woff2');
}

63
src/scss/_vars.scss Normal file
View File

@@ -0,0 +1,63 @@
// sass-lint:disable no-color-literals
// =========
// Colors. Names from http://chir.ag/projects/name-that-color/
// =========
$black: #000;
$white: #fff;
$mine-shaft: #333;
$royal-blue: #44d;
$havelock-blue: #67d;
$catskill-white: #f7f9fb;
$cod-gray: #111;
$big-stone: #123;
$rhino: #346;
$athens-gray: #f8f8f9;
$mischka: #d5d9e2;
$pine-green: #077;
$purple-heart: #62b;
$cardinal: #c23;
$mirage: #1a2028;
$pickled-bluewood: #293845;
$facebook: #3b5998;
$spindle: #bce;
$dodger-blue: #3af;
$pattens-blue: #def;
$stratos: #001450;
$gray-brown: #f9f8f2;
$bg-colors: (
'primary': $royal-blue,
'secondary': $havelock-blue,
'light': $catskill-white,
'black': $cod-gray,
'black-blue': $big-stone,
'blue': $rhino,
'brown': $gray-brown,
'gray': $mischka,
'green': $pine-green,
'purple': $purple-heart,
'red': $cardinal,
'white': $white,
// Branding
'facebook': $facebook
) !default;
$social-nav: (
'twitter': #1da1f3,
'facebook': $facebook,
'linkedin': #1683bb,
'dribbble': #ea4c89,
'github': #60b044,
'email': #dd4b39
) !default;
$body-color: $mine-shaft !default;
$body-bg: $catskill-white !default;
$focus-box-shadow: 0 0 2px rgba(150, 187, 238, 1) !default;
$link-color: $royal-blue !default;
$link-color-secondary: $cardinal !default;
$link-hover: $dodger-blue !default;
$hr-bg: radial-gradient(ellipse at center, rgba(0, 20, 80, .2) 0, rgba(255, 255, 255, 0) 75%) !default;
$current-zoomed-slide-shadow: 0 0 7px rgba(0, 187, 255, .5);
$index-overlay: rgba(0, 10, 40, .8);

98
src/scss/full.scss Normal file
View File

@@ -0,0 +1,98 @@
/*-----------------------------------------------------------------------------------
0. CSS Reset & Normalize
1. Base
1.1 Wrap/Container
1.2 Animations
1.3 Responsive Media (videos, iframe, screenshots...)
1.4 Basic Grid (2,3,4 columns)
2. Typography & Lists
2.1 Headings with background
2.2 Classes: .text-
2.3 San Francisco Font (Apple)
3. Header & Footer
3.1 Logo
4. Navigation
4.1 Navbars
5. SLIDES (vertically and horizontally centered)
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
6.2 .flexblock.clients
6.3 .flexblock.steps
6.4 .flexblock.metrics
6.5 .flexblock.specs
6.6 .flexblock.reasons
6.7 .flexblock.gallery
6.8 .flexblock.plans
6.9. flexblock.activity
7. Promos/Offers (pricing, tagline, CTA...)
8. Work / Resume / CV
9. Table of contents
10. Cards
11. Quotes
12. Avatars
13. Tables
14. Forms
15. Longform Elements
16. Safari Bug (flex-wrap)
17. Slidex index (aka zoom)
18. Print
19. Colors
----------------------------------------------------------------------------------- */
@import 'vars';
@import 'utils/mixins';
@import 'utils/reset';
@import 'utils/clear';
@import 'base';
@import 'utils/animations';
@import 'modules/media';
@import 'modules/browser';
@import 'modules/grid';
@import 'typography';
@import 'modules/header-footer';
@import 'modules/logo';
@import 'modules/navigation';
@import 'modules/slides';
@import 'modules/slides-bg';
@import 'modules/slides-navigation';
@import 'modules/flexblock';
@import 'modules/flexblock-features';
@import 'modules/flexblock-clients';
@import 'modules/flexblock-steps';
@import 'modules/flexblock-metrics';
@import 'modules/flexblock-specs';
@import 'modules/flexblock-reasons';
@import 'modules/flexblock-gallery';
@import 'modules/flexblock-plans';
@import 'modules/flexblock-activity';
@import 'modules/promos';
@import 'modules/work';
@import 'modules/toc';
@import 'modules/cards';
@import 'modules/quotes';
@import 'modules/avatars';
@import 'modules/tables';
@import 'modules/form';
@import 'modules/button';
@import 'modules/badges';
@import 'modules/longform';
@import 'utils/bugs';
@import 'modules/zoom';
@import 'modules/print';
@import 'color';

View File

@@ -0,0 +1,22 @@
/*=========================================
12. Avatars - uifaces.com
=========================================== */
cite img,
img[class*='avatar-'] {
display: inline-block;
margin-right: 6px;
vertical-align: middle;
}
img[class*='avatar-'] {
border-radius: 50%;
}
$avatar-sizes: 40, 48, 56, 64, 72, 80;
@each $size in $avatar-sizes {
img.avatar-#{$size} {
@include square(#{$size}px);
}
}

View File

@@ -0,0 +1,43 @@
/*=== App Store Badges === */
/* Change width and height: 216x64px, 162x48px, 135x40... */
[class*='badge-'] {
background-repeat: no-repeat;
background-size: cover;
border-radius: .6rem;
display: inline-block;
height: 40px;
line-height: 4rem;
text-indent: -4000px;
width: 135px;
&:hover {
opacity: .7;
}
@media (min-width: 1024px) {
height: 48px;
line-height: 4.8rem;
width: 162px;
}
@media (min-width: 500px) {
& + & {
margin-left: 1.8rem;
}
}
@media (max-width: 499px) {
& + & {
margin-top: .8rem;
}
}
}
.badge-ios {
background-image: url('../images/bt-appstore.png');
}
.badge-android {
background-image: url('../images/bt-playstore.png');
}

View File

@@ -0,0 +1,39 @@
/*=== HTML Browser (Screenshots) ================ */
/* <figure class="browser"> img </figure> */
.browser {
border-radius: .3rem;
margin: 0 auto 3.2rem;
max-width: 1024px;
overflow: hidden;
li & {
margin-bottom: 0;
}
h1 + &,
h2 + &,
p + & {
margin-top: 4.8rem;
}
figcaption {
padding: 2.4rem;
}
&:before {
content: '● ● ●';
font-size: .8rem;
left: 0;
line-height: 0;
padding: 1.6rem;
position: absolute;
text-align: left;
top: 0;
width: 100%;
@media (min-width: 768px) {
font-size: 1.6rem;
}
}
}

View File

@@ -0,0 +1,14 @@
/* Buttons/Badges */
[class*='button'] {
@media (min-width: 500px) {
& + & {
margin-left: 1.8rem;
}
}
@media (max-width: 499px) {
& + & {
margin-top: .8rem;
}
}
}

View File

@@ -0,0 +1,140 @@
/*===========================================
10. Cards
============================================= */
[class*='card-'] {
&,
& > a {
clear: both;
display: flex;
flex-direction: row;
position: relative;
}
.fullscreen &,
.fullscreen & > a {
min-height: 100vh;
}
figure img,
figure iframe {
display: block;
margin: 0 auto;
}
figure figcaption {
bottom: 0;
font-size: 1.4rem;
left: 0;
line-height: 2.4rem;
padding: .8rem 2.4rem;
position: absolute;
z-index: 2;
svg {
font-size: 1rem;
}
}
}
@media (min-width: 768px) {
[class*='card'][class*='bg-'] figure,
.fullscreen [class*='card'] figure {
max-height: 100%;
min-width: 380px;
text-align: center;
vertical-align: middle;
}
[class*='card-'][class*='bg-'] figure img,
[class*='card-'][class*='bg-'] figure iframe,
.fullscreen [class*='card-'] figure img,
.fullscreen [class*='card-'] figure iframe {
height: 100%;
left: 0;
object-fit: cover;
position: absolute;
top: 0;
width: 100%;
z-index: 1;
}
}
.flex-content,
[class*='card'] blockquote {
padding: 2.4rem;
position: relative;
}
[class*='card-'] .flex-content,
[class*='card-'] blockquote {
display: flex;
flex-direction: column;
justify-content: center;
}
.flex-content p {
position: relative;
}
@media (min-width: 768px) {
.card-50 figure,
.card-50 blockquote,
.card-50 .flex-content {
width: 50%;
}
.card-30 figure,
.card-70 .flex-content,
.card-70 blockquote {
width: 30%;
}
.card-40 figure,
.card-60 .flex-content,
.card-60 blockquote {
width: 40%;
}
.card-60 figure,
.card-40 .flex-content,
.card-40 blockquote {
width: 60%;
}
.card-70 figure,
.card-30 .flex-content,
.card-30 blockquote {
width: 70%;
}
[class*='card']:nth-child(odd) figure {
order: 0;
}
[class*='card']:nth-child(even) figure {
order: 1;
}
.flex-content,
[class*='card'] blockquote {
padding: 4.8rem;
}
.fullscreen [class*='card'] .flex-content,
.fullscreen [class*='card'] blockquote {
padding: 6.4rem;
}
}
@media (max-width: 767px) {
[class*='card-'],
[class*='card-'] > a {
flex-flow: column;
}
.card figure,
.card header {
width: 100%;
}
}

View File

@@ -0,0 +1,58 @@
/*===========================================
6.9 Block Activity <ul class="activity">
CV / News
============================================= */
.flexblock.activity {
flex-direction: column;
li {
flex: 1;
position: relative;
width: auto;
}
p {
margin-bottom: 0;
vertical-align: top;
}
img {
display: block;
}
.year,
.title {
display: inline;
font-weight: 600;
}
.summary {
width: 100%;
}
.title {
margin-left: 1rem;
}
@media (min-width: 768px) {
p {
float: left;
}
.year {
width: 15%;
}
.title {
margin-left: 4%;
margin-right: 4%;
width: 27%;
}
.summary {
width: 50%;
}
}
}

View File

@@ -0,0 +1,38 @@
/*=====================================================================
6.2 Clients Logos <ul class="flexblock clients">
======================================================================= */
.flexblock.clients.blink li > a,
.flexblock.clients li {
padding: 0;
}
.flexblock.clients li figcaption {
padding: 0 2.4rem 2.4rem;
}
.flexblock.clients.border li figcaption {
padding-top: 2.4rem;
}
.clients.blink li>a,
.clients li {
justify-content: inherit;
}
.clients li img,
.clients li svg {
display: block;
padding: 2.4rem;
}
.clients.border li img,
.clients.border li svg {
display: block;
margin-left: auto;
margin-right: auto;
}
.clients li:hover {
z-index: 1;
}

View File

@@ -0,0 +1,77 @@
/*====================================================================
6.1 Features <ul class="flexblock features">
====================================================================== */
.flexblock.features {
> li {
border-radius: .4rem;
margin-bottom: 4.8rem;
width: 100%;
}
li h2 {
text-transform: uppercase;
}
li span {
font-weight: 300;
}
li p {
margin: 0;
}
li p em {
display: block;
}
li span,
li svg {
display: block;
font-size: 6.4rem;
line-height: 1;
margin: 0;
}
li img {
width: 6.4rem;
}
li span sup {
font-size: 3rem;
}
@media (min-width: 1200px) {
li span,
li svg,
li img {
float: left;
margin-right: .8rem;
}
}
}
@media (min-width: 768px) {
.flexblock.features {
margin-left: -2%;
margin-right: -2%;
}
.flexblock.features > li {
margin-left: 2%;
margin-right: 2%;
width: 29%;
}
.size-50 .flexblock.features > li {
width: 46%;
}
.column .flexblock.features > li {
width: 100%;
}
footer .flexblock.features>li {
margin-bottom: 0;
}
}

View File

@@ -0,0 +1,141 @@
/*=================================================
6.7 Gallery - <ul class="flexblock gallery">
Block Thumbnails li+.overlay+image
img size recommended:800x600px
=================================================== */
.flexblock.gallery {
li {
margin-bottom: 4.8rem;
&:nth-child(n+4) {
flex: inherit;
}
figcaption {
padding: 1.6rem;
position: relative;
&:before {
content: '';
height: 0;
left: 20%;
margin-left: -.5em;
position: absolute;
top: .4rem;
transform: rotate(135deg);
transform-origin: 0 0;
transition: .1s;
width: 0;
}
}
&:hover figcaption:before {
top: .3rem;
}
}
.aligncenter & li figcaption:before {
left: 55%;
margin-left: 0;
}
li,
&.blink li > a {
padding: 0;
}
h2 {
text-transform: uppercase;
}
h2 + p,
h3 + p {
margin-top: .8rem;
}
p {
font-size: 1.6rem;
line-height: 2.4rem;
margin-bottom: 0;
}
li footer {
margin-top: .8rem;
padding: 1.2rem 0 0;
position: relative;
}
li img {
display: block;
margin-left: auto;
margin-right: auto;
}
@media (min-width: 600px) {
margin-left: -2%;
margin-right: -2%;
li {
margin-left: 2%;
margin-right: 2%;
width: 46%;
}
}
}
@media (min-width: 1024px) {
.flexblock.gallery li {
width: 21%;
}
.grid.sm .flexblock.gallery li,
.grid.ms .flexblock.gallery li {
width: 29%;
}
.grid.sms .flexblock.gallery li {
width: 46%;
}
}
.overlay {
bottom: 0;
cursor: pointer;
display: flex;
flex-direction: column;
height: 100%;
justify-content: center;
left: 0;
opacity: 1;
position: absolute;
right: 0;
top: 0;
transition: all .3s linear;
width: 100%;
z-index: 2;
}
li .overlay {
align-items: center;
}
li .overlay h2 {
letter-spacing: .2rem;
margin: 0;
padding: 0 2.4rem;
text-align: center;
text-transform: uppercase;
width: 100%;
}
.overlay p,
.overlay time {
margin-bottom: 0;
}
li:hover .overlay {
cursor: pointer;
}

View File

@@ -0,0 +1,32 @@
/*=================================================
6.4 Block Numbers - <ul class="flexblock metrics">
=================================================== */
.metrics li {
text-align: center;
width: 100%;
@media (min-width: 568px) {
width: 50%;
}
@media (min-width: 1024px) {
width: 25%;
}
}
.metrics li strong {
display: block;
}
.metrics li span,
.metrics li svg {
display: block;
font-size: 6.4rem;
line-height: 7.2rem;
margin: 0 auto;
}
.card-50 .metrics li {
width: 50%;
}

View File

@@ -0,0 +1,85 @@
/*===============================================
6.8 Plans / Pricing <ul class="flexblock plans">
================================================= */
.flexblock.plans {
> li {
border-radius: 3px;
margin-bottom: 4.8rem;
text-align: center;
z-index: 1;
}
li,
&.blink li>a {
padding: 0;
}
&.blink li > a div,
li div {
padding-bottom: 3.2rem;
}
li p,
li h2 {
padding: .8rem 3.2rem;
}
li h2 {
float: left;
font-weight: 400;
letter-spacing: .1rem;
text-transform: uppercase;
width: 100%;
}
.price {
clear: both;
display: block;
font-size: 4.8rem;
font-weight: 400;
line-height: 6.2rem;
padding: 2.4rem;
sup {
font-size: 1.8rem;
margin-right: .4rem;
}
li ul {
margin-bottom: 2.4rem;
}
}
li ul li {
display: block;
padding: .8rem 3.2rem;
text-align: left;
width: 100%;
}
@media (min-width: 1024px) {
margin-left: -2%;
margin-right: -2%;
>li {
margin-left: 2%;
margin-right: 2%;
width: 29%;
}
>li:hover,
>li:nth-child(2) {
position: relative;
transform: scale(1.08);
z-index: 2;
}
&:hover li:nth-child(2):not(:hover) {
position: relative;
transform: scale(1);
z-index: 1;
}
}
}

View File

@@ -0,0 +1,41 @@
/*=================================================
6.6 Reasons/Why/Numbers (counter-increment)
<ul class="flexblock reasons">
=================================================== */
.flexblock.reasons {
li {
counter-increment: list;
text-align: left;
width: 100%;
&:hover {
transform: translateY(-.2rem);
}
&:after {
bottom: -2.4rem;
content: '';
display: block;
height: 1px;
position: relative;
}
&:before {
content: counter(list)'.';
font-size: 6.4rem;
line-height: 1;
}
@media (min-width: 768px) {
padding-left: 8.8rem;
/* You need two digits? (1-10)*/
/*padding-left: 12rem; */
&:before {
left: 2.4rem;
position: absolute;
}
}
}
}

View File

@@ -0,0 +1,49 @@
/*=====================================================
6.5 Specs/Items: <ul class="flexblock specs">
======================================================= */
.specs li {
text-align: left;
width: 100%;
&:after {
bottom: -2.4rem;
content: '';
display: block;
height: 1px;
position: relative;
}
&:hover {
transform: translateX(.2rem);
}
span,
svg {
display: block;
font-size: 6.4rem;
line-height: 1;
margin: 0;
}
img {
width: 6.4rem;
}
span {
font-weight: 300;
sup {
font-size: 3rem;
}
}
@media (min-width: 1024px) {
span,
svg,
img {
float: left;
margin-right: 2.4rem;
}
}
}

View File

@@ -0,0 +1,38 @@
/*==================================================
6.3 flexblock.steps <ul class="flexblock steps">
About, Philosophy...
=================================================== */
.steps li {
width: 100%;
img,
span {
display: block;
margin: 0 auto .8rem;
}
span {
font-size: 6.4rem;
}
@media (min-width: 768px) {
width: 50%;
}
}
@media (min-width: 1024px) {
.steps li {
width: 25%;
}
.process {
border-left-style: solid;
border-left-width: 15px;
height: 0;
left: 0;
position: absolute;
top: 60px;
width: 0;
}
}

View File

@@ -0,0 +1,101 @@
/*===============================================================
6. Magic blocks with flexbox (Auto-fill & Equal Height)
Blocks Links li>a = .flexblock.blink (.blink required)
================================================================= */
.flexblock {
clear: both;
display: flex;
flex-wrap: wrap;
margin-left: auto;
margin-right: auto;
padding: 0;
&:after {
clear: both;
}
&:before {
content: '';
display: table;
}
li,
&.blink li > a {
display: flex;
flex-direction: column;
margin: 0;
padding: 2.4rem;
position: relative;
}
li {
flex: auto;
text-align: left;
transition: .3s;
width: 100%;
&:hover {
transform: translateY(-.2rem);
}
@media (min-width: 600px) {
width: 50%;
}
@media (min-width: 1024px) {
width: 25%;
}
}
&.aligncenter li {
text-align: center;
}
&.vertical-align li {
justify-content: center;
}
&.blink li {
padding: 0;
}
li h2 svg,
li h3 svg {
margin-top: 0;
}
}
h1 + .flexblock,
h2 + .flexblock,
h3 + .flexblock,
div + ul,
div + ol {
margin-top: 3.2rem;
}
.flexblock li h2,
.flexblock li h3,
footer .column h2,
footer .column h3 {
font-size: 1.8rem;
font-weight: 600;
line-height: 3.2rem;
margin-bottom: 0;
}
.flexblock li li,
.flexblock.blink li li {
padding: 0;
width: 100%;
}
[class*='content-'] .flexblock li p {
font-size: 1.8rem;
line-height: 3.2rem;
}
.content-right .flexblock.features li,
.content-left .flexblock.features li {
width: 46%;
}

159
src/scss/modules/_form.scss Normal file
View File

@@ -0,0 +1,159 @@
/*=========================================
14. Forms
=========================================== */
form {
text-align: left;
& + p,
input + p,
textarea + p {
margin-top: .8rem;
}
}
input[type='text'],
input[type='email'],
input[type='tel'],
input[type='url'],
input[type='search'],
input[type='password'] {
appearance: none;
border-radius: 0;
}
input,
button,
select {
display: inline-block;
font-size: 1.6rem;
font-weight: 400;
height: 4.8rem;
margin: 0;
padding: .7rem;
position: relative;
width: 100%;
}
input[type='radio'],
input[type='checkbox'] {
height: auto;
padding: 4px;
width: auto;
}
button[type='submit'],
textarea {
width: 100%;
}
textarea {
padding: .7rem;
}
button {
cursor: pointer;
text-align: center;
width: auto;
}
.button {
cursor: pointer;
display: inline-block;
font-size: 1.8rem;
font-weight: 400;
line-height: 4.8rem;
min-width: 16rem;
padding: 0 1.6rem;
text-align: center;
svg {
font-size: 2.4rem;
}
}
.button.radius,
input.radius {
border-radius: 2.4rem;
}
button,
input[type='submit'] {
font-weight: 400;
letter-spacing: .1rem;
text-transform: uppercase;
}
.plans .button {
margin-left: auto;
margin-right: auto;
width: 50%;
}
.try {
display: block;
font-size: 1.6rem;
margin-top: 1.6rem;
}
fieldset {
padding: 2.4rem;
}
legend {
border: 0;
font-weight: 400;
letter-spacing: .1rem;
padding: 1.6rem 2.4rem;
text-align: center;
text-transform: uppercase;
width: 100%;
}
input:focus,
textarea:focus,
select:focus {
border-width: 1px;
}
a.button:hover,
button[type='submit']:hover,
input[type='submit']:hover {
transform: scale(1.01);
}
:disabled,
button:disabled:hover {
cursor: not-allowed;
}
.user {
input {
margin-bottom: 0;
&[type='email'],
&[type='search'],
&[type='text'] {
width: 100%;
@media (min-width: 500px) {
float: left;
width: 70%;
}
}
}
button,
input[type='submit'] {
left: 0;
width: 100%;
@media (min-width: 500px) {
cursor: pointer;
width: 30%;
}
}
}

View File

@@ -0,0 +1,59 @@
/*=== 1.4. Basic Grid (Flexible blocks)
Auto-fill & Equal height === */
.grid {
clear: both;
display: flex;
flex-wrap: wrap;
margin-left: auto;
margin-right: auto;
&:after {
clear: both;
}
&:before {
content: '';
display: table;
}
& > .column {
display: flex;
flex: auto;
flex-direction: column;
padding: 2.4rem;
position: relative;
transition: .3s;
width: 100%;
}
&.vertical-align .column {
justify-content: center;
}
@media (min-width: 768px) {
& > .column {
width: 25%;
}
&.sm .column:nth-child(1) {
width: 30%;
}
&.sm .column:nth-child(2) {
width: 70%;
}
&.ms .column:nth-child(1) {
width: 70%;
}
&.ms .column:nth-child(2) {
width: 30%;
}
&.sms .column:nth-child(2) {
width: 50%;
}
}
}

View File

@@ -0,0 +1,64 @@
/*=========================================
3. Header & Footer
=========================================== */
/* -- If you want an unique, global header/footer,read this:
https://github.com/webslides/webslides/issues/57 -- */
header,
footer,
#navigation {
padding: 2.4rem;
transition: all .4s ease-in-out;
width: 100%;
}
header p,
footer p {
line-height: 4.8rem;
margin-bottom: 0;
}
header[role='banner'] img,
footer img {
height: 4rem;
vertical-align: middle;
}
footer {
position: relative;
}
header,
footer {
z-index: 3;
}
header,
.ws-ready footer {
left: 0;
position: absolute;
top: 0;
}
.ws-ready footer {
bottom: 0;
top: auto;
}
// Remove "opacity=0" if you want an unique, visible header on each slide
header[role='banner'] {
opacity: 0;
&:hover {
opacity: 1;
}
}
@media (max-width: 767px) {
footer .alignleft,
footer .alignright {
display: block;
float: none;
}
}

View File

@@ -0,0 +1,17 @@
/*=== 3.1. Logo === */
.logo {
text-transform: lowercase;
a {
background: url('../images/logos/logo.svg') no-repeat 0 0;
background-size: 4.8rem;
float: left;
height: 4.8rem;
text-indent: -4000px;
/*If you remove text-indent and add: */
/*padding-left: 6rem;*/
vertical-align: middle;
width: 4.8rem;
}
}

View File

@@ -0,0 +1,67 @@
/*=========================================
15. Longform
=========================================== */
/* -- Posts = .wrap.longform -- */
.longform {
width: 72rem;
/* Why 72rem=720px?
90-95 characters per line = better reading speed */
& .alignleft,
& .alignright {
max-width: 40%;
}
img.aligncenter,
figure.aligncenter {
margin-bottom: 3.2rem;
margin-top: 3.2rem;
}
ul,
ol {
margin-bottom: 3.2rem;
}
ul ol,
ol ul,
ul ul,
ol ol {
margin-bottom: 0;
}
figcaption p,
[class*='text-pull-'] p {
font-size: 1.6rem;
line-height: 2.4rem;
}
/* Mobile: video full width */
.text-pull.embed {
margin-left: -2.4rem;
margin-right: -2.4rem;
padding-bottom: 60.6%;
}
@media (min-width: 1280px) {
[class*='text-pull-'] {
max-width: 32%;
}
.text-pull-right {
margin-right: -256px;
}
.text-pull-left {
margin-left: -256px;
}
}
@media (min-width: 1024px) {
.text-quote {
margin-left: -4.8rem;
margin-right: -4.8rem;
}
}
}

View File

@@ -0,0 +1,61 @@
/*=== 1.3 Responsive Media (videos, iframe...) === */
.embed {
height: 0;
overflow: hidden;
/*aspect ratio:16:9*/
padding-bottom: 56.6%;
/*aspect ratio: 4:3*/
/*padding-bottom: 75%;*/
position: relative;
iframe,
object,
embed,
video {
height: 100%;
left: 0;
margin: 0;
position: absolute;
top: 0;
width: 100%;
}
/* -- Responsive background video
https://fvsch.com/code/video-background/ -- */
.fullscreen > & {
bottom: 0;
height: auto;
left: 0;
padding-bottom: 0;
position: fixed;
right: 0;
top: 0;
/* 1. No object-fit support: */
& > iframe,
& > object,
& > embed,
& > video {
@media (min-aspect-ratio: 16 / 9) {
height: 300%;
top: -100%;
}
@media (max-aspect-ratio: 16 / 9) {
left: -100%;
width: 300%;
}
/* 2. If supporting object-fit, overriding (1): */
@supports (object-fit: cover) {
height: 100%;
left: 0;
object-fit: cover;
top: 0;
width: 100%;
}
}
}
}

View File

@@ -0,0 +1,72 @@
/*=========================================
4. Navigation
=========================================== */
/*=== 4.1. Navbars === */
nav ul {
display: flex;
flex-wrap: wrap;
/*====align left====*/
justify-content: flex-start;
/* ==== align center ====*/
/*justify-content: center; */
/*====align right====*/
/* justify-content: flex-end; */
/*====separated columns li a====*/
/* justify-content: space-between; */
/*====separated columns centered li a====*/
/*justify-content: space-around;*/
li {
float: left;
list-style: none;
position: relative;
}
}
nav ul li:first-child,
nav[role='navigation'] ul li {
margin-left: 0;
}
nav[role='navigation'] li a {
display: flex;
justify-content: center;
line-height: 4.8rem;
max-width: 100%;
padding: 0 1.6rem;
position: relative;
text-decoration: none;
svg {
margin: 1.5rem .4rem 1.5rem 0;
}
}
header nav ul {
justify-content: flex-end;
margin: 0;
}
nav.aligncenter ul,
.aligncenter nav ul {
/* ==== align center ====*/
justify-content: center;
}
nav.navbar ul li {
/*====full float li a ====*/
flex: 1 1 auto;
}
@media (max-width: 568px) {
nav.navbar ul {
flex-flow: column wrap;
padding: 0;
}
nav.navbar li a {
justify-content: flex-start;
}
}

View File

@@ -0,0 +1,52 @@
/*=========================================
17. PRINT
=========================================== */
// sass-lint:disable no-important
@media print {
@page {
margin: .5cm;
size: A4 landscape;
}
// Black prints faster
* {
background: transparent !important;
color: $black !important;
filter: none !important;
text-shadow: none !important;
}
html,
body,
#webslides {
height: auto !important;
overflow: auto !important;
width: auto !important;
}
#webslides {
overflow-x: auto !important;
overflow-y: auto !important;
}
section,
.slide {
display: flex !important;
height: auto !important;
}
section * {
animation: none;
}
table,
figure {
page-break-inside: avoid;
}
#counter,
#navigation {
display: none;
}
}

View File

@@ -0,0 +1,98 @@
/*=============================================
7. Promos/Offers (pricing, tagline, CTA...)
=============================================== */
.cta {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.number,
.cta .benefit {
display: flex;
flex-direction: column;
justify-content: center;
max-width: 100%;
padding: .8rem;
}
.number {
text-align: center;
}
.cta .benefit {
max-width: 100%;
text-align: center;
}
.number span {
display: block;
font-size: 8rem;
line-height: 8rem;
}
.number span sup {
font-size: 4rem;
}
.cta p {
margin-bottom: 0;
}
@media (min-width: 768px) {
.number,
.cta .benefit {
max-width: 50%;
padding: 4.8rem;
}
.cta .benefit {
text-align: left;
}
.number span {
font-size: 16rem;
line-height: 16rem;
sup {
font-size: 6rem;
vertical-align: middle;
}
}
}
/* --- Header CTA --- */
.cta-cover {
display: table;
width: 100%;
h1 strong {
font-weight: 400;
}
@media (min-width: 1024px) {
h1 {
float: left;
max-width: 80%;
}
h1 strong {
display: block;
}
.button {
margin-top: 1.2rem;
}
.try {
text-align: center;
}
}
@media (max-width: 1023px) {
.alignright {
float: none;
}
}
}

View File

@@ -0,0 +1,71 @@
/*=========================================
11. Quotes
=========================================== */
blockquote {
display: inline-block;
position: relative;
p {
font-size: 2.4rem;
line-height: 4rem;
&:last-child {
margin-bottom: 3.2rem;
}
}
}
/* -- Interviews dl.text-interview -- */
dd blockquote p:last-child {
margin-bottom: 0;
}
cite {
display: block;
text-align: center;
&:before {
content: '\2014 \2009';
margin-right: 6px;
}
}
cite span {
display: block;
}
/* -- A big Blockquote -- */
/* .wall will be deprecated soon. Use .text-quote ;) */
.text-quote,
.wall {
/* Versatility: blockquote, p, h2... */
position: relative;
&:before {
content: '\201C';
font-family: arial, sans-serif;
font-size: 12rem;
height: 5.6rem;
left: -.8rem;
line-height: 1;
position: absolute;
text-align: center;
top: -4rem;
width: 5.6rem;
}
@media (min-width: 768px) {
padding-left: 6.4rem;
p {
font-size: 3.2rem;
line-height: 4.8rem;
}
&:before {
left: .8rem;
top: -1.6rem;
}
}
}

View File

@@ -0,0 +1,126 @@
/*=== 5.3 Slides - Background Images/Videos === */
.background,
[class*='background-'] {
background-repeat: no-repeat;
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0;
}
/*=== BG Positions === */
.background {
background-position: center;
background-size: cover;
&-top {
background-position: top;
background-size: cover;
}
&-bottom {
background-position: bottom;
background-size: cover;
}
&-center {
background-position: center;
}
&-center-top {
background-position: center top;
}
&-right-top {
background-position: right top;
}
&-left-top {
background-position: left top;
}
&-center-bottom,
&-left-bottom,
&-right-bottom,
&-left,
&-right {
background-position: center bottom;
}
@media (min-width: 1024px) {
&-left-bottom {
background-position: left bottom;
}
&-right-bottom {
background-position: right bottom;
}
&-right {
background-position: right;
}
&-left {
background-position: left;
}
}
/*fullscreen video
<video class="background-video">
*/
&-video {
height: 100%;
object-fit: fill;
width: 100%;
}
}
/*=== bg image/video overlay === */
/*-- [class*="bg-"] .background.dark, [class*="bg-"] .embed.dark... -- */
[class*='bg-'] .light,
[class*='bg-'] .light {
opacity: .8;
}
[class*='bg-'] .dark,
[class*='bg-'] .dark {
opacity: .2;
}
[class*='bg-'] .background-video.dark {
opacity: .5;
}
@media (max-width: 1023px) {
[class*='background-'] {
animation: fadeIn ease-in .2;
opacity: .2;
}
.background-video {
opacity: .8;
}
}
/*=== Animated Background Image === */
.background.anim {
animation: anim 80s linear infinite;
background-position: center top;
background-repeat: repeat;
background-size: 100%;
height: 200%;
}
/*=== Background with a frame === */
/*<span class="background" style="background-image:url('image.jpg')"></span>
<span class="background frame"></span>*/
[class*='background'].frame {
margin: 2.4rem;
}

View File

@@ -0,0 +1,70 @@
/* === 5.2 Counter / Navigation Slides === */
#navigation {
animation: fadeIn 8s;
bottom: 0;
left: 0;
margin-left: auto;
margin-right: auto;
opacity: 0;
position: fixed;
right: 0;
width: 24.4rem;
/* hover/visibility */
z-index: 4;
&:hover {
opacity: 1;
}
p {
margin-bottom: 0;
}
}
#counter {
display: block;
line-height: 4.8rem;
margin-left: auto;
margin-right: auto;
position: relative;
text-align: center;
width: 10rem;
a:hover {
padding: .8rem;
}
}
a#next,
a#previous {
border-radius: .4rem;
cursor: pointer;
font-size: 2.4rem;
height: 4rem;
padding: .8rem;
position: absolute;
text-align: center;
width: 4rem;
}
a#next {
right: 3.2rem;
}
a#previous {
left: 3.2rem;
}
@media (max-width: 1024px) {
#navigation {
animation: fadeIn 6s;
background: url('../images/swipe.svg') no-repeat center top;
background-size: 4.8rem;
}
#navigation a,
#counter {
display: none;
}
}

View File

@@ -0,0 +1,118 @@
/*============================================
5. SLIDES (Full Screen)
Vertically and horizontally centered
============================================== */
/* Fade transition to all slides.
* = All HTML elements will have those styles.*/
section * {
animation: fadeIn .6s ease-in-out;
}
section .background,
section .light,
section .dark {
animation-duration: 0s;
}
/*=== Section = Slide === */
section,
.slide {
display: flex;
flex-direction: column;
justify-content: center;
min-height: 100vh; /*Fullscreen*/
/* Prototyping? min-height: 720px (Baseline: 8px = .8rem)*/
padding: 2.4rem;
/*Fixed/Visible header? padding-top: 12rem; */
page-break-after: always;
position: relative;
word-wrap: break-word;
@media (min-width: 1024px) {
padding-bottom: 12rem;
padding-top: 12rem;
}
}
/*slide with no padding (full card, .embed youtube video...) */
.fullscreen {
padding: 0;
/* Fixed/Visible header?
padding:8.2rem 0 0 0;
*/
}
/* slide alignment - top */
.slide-top {
justify-content: flex-start;
}
/* slide alignment - bottom */
.slide-bottom {
justify-content: flex-end;
}
/*== 5.1. Mini container width:50%
Aligned items [class*="content-"]=== */
[class*='content-'] {
position: relative;
text-align: left;
}
.wrap[class*='bg-'],
.wrap.frame,
[class*='content-'][class*='bg-'],
[class*='content-'].frame,
[class*='align'][class*='bg-'] {
padding: 4.8rem;
}
form[class*='bg-'] {
padding: 2.4rem;
}
[class*='content-'] > [class*='content-'] p {
font-size: 1.8rem;
line-height: 3.2rem;
}
.content-center {
margin: 0 auto;
text-align: center;
}
@media (min-width: 768px) {
[class*='content-'] {
width: 50%;
&:after,
&:before {
content: '';
display: table;
}
&:after {
clear: both;
}
}
.content-left {
float: left;
}
.content-right {
float: right;
}
[class*='content-'] + [class*='content-'] {
margin-bottom: 4.8rem;
padding-left: 2.4rem;
}
[class*='content-'] + [class*='size-'] {
clear: both;
margin-top: 6.4rem;
}
}

View File

@@ -0,0 +1,34 @@
/*=========================================
13. Tables
=========================================== */
table {
margin-bottom: 3.2rem;
margin-top: 3.2rem;
}
td,
th,
thead {
border-spacing: 0;
padding: .7rem 2.4rem;
}
thead th,
th {
cursor: default;
font-weight: 600;
text-align: left;
text-transform: uppercase;
white-space: nowrap;
}
thead,
td.goals {
font-weight: 600;
text-shadow: none;
}
tr > td {
font-weight: 400;
}

View File

@@ -0,0 +1,77 @@
/*===========================================
9. Table of contents
============================================= */
.toc,
.toc ol > li:before,
.chapter {
position: relative;
z-index: 2;
}
.toc {
ol {
counter-reset: item;
position: relative;
& > li:before {
content: counters(item, '.') '. ';
display: table-cell;
padding-right: .8rem;
width: 2.4rem;
}
li li:before {
content: counters(item, '.') ' ';
}
}
li {
counter-increment: item;
display: table;
font-weight: 400;
margin-bottom: .8rem;
margin-left: 0;
transition: .3s;
width: 100%;
li {
font-weight: 300;
margin-bottom: 0;
margin-left: 0;
}
.toc-page:before {
content: '';
display: block;
left: 0;
margin-top: 1.8rem;
position: absolute;
right: 4rem;
}
& > a {
display: inline-block;
width: 100%;
}
a:hover span {
font-weight: 600;
}
a:hover .toc-page:before {
border-bottom-width: 2px;
}
}
}
.chapter {
display: inline-block;
font-size: 1.8rem;
line-height: 3.2rem;
padding-right: .8rem;
}
.toc-page {
float: right;
}

107
src/scss/modules/_work.scss Normal file
View File

@@ -0,0 +1,107 @@
/*=========================================
8. Work/Resumé/CV <ul class="work">
=========================================== */
.work {
clear: both;
display: flex;
flex-direction: column;
text-align: left;
h1 + &,
h2 + &,
h3 + &,
p + & {
margin-top: 4.8rem;
}
li {
flex: 1;
list-style: none;
margin: 0;
position: relative;
}
p {
margin-bottom: 0;
transition: .3s;
}
li a {
display: block;
float: left;
height: 100%;
padding: 2.4rem 0;
width: 100%;
}
li p {
padding-left: 1.2rem;
}
li.work-label p {
padding-left: 0;
}
li a:hover p:first-child {
padding-left: 1.6rem;
}
li p:last-child {
position: absolute;
right: 1.2rem;
top: 2.4rem;
}
li.work-label p:last-child {
right: 0;
top: 0;
}
&-label {
float: left;
font-weight: 600;
padding: 0 0 2.4rem;
width: 100%;
}
&-title {
display: block;
padding-right: 1.2rem;
width: 75%;
}
}
@media (min-width: 768px) {
.work-label p,
.work li p {
float: left;
margin-right: 2%;
width: 25%;
}
.work li.work-label p:last-child,
.work li p:last-child {
float: right;
margin-right: 0;
padding-right: 1.2rem;
position: relative;
right: auto;
text-align: right;
top: auto;
}
.work li p.work-date {
width: 120px;
}
}
@media (max-width: 768px) {
.work-client,
.work-label .work-services {
clip: rect(1px, 1px, 1px, 1px);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
}

155
src/scss/modules/_zoom.scss Normal file
View File

@@ -0,0 +1,155 @@
/*==============================================
18. Slides Index: Thumbnails navigation gallery
================================================ */
#webslides-zoomed {
align-content: flex-start;
align-items: flex-start;
flex-direction: row;
justify-content: flex-start;
min-height: 100vh;
position: relative;
z-index: 2;
&.disabled {
left: -100000px;
position: absolute;
}
.slide {
height: 400%;
width: 400%;
@media screen and (orientation: portrait), screen and (max-width: 768px) and (orientation: landscape) {
height: 200%;
width: 200%;
}
@media (max-aspect-ratio: 2 / 3) {
height: 200%;
width: 200%;
}
}
> .wrap {
@media (min-width: 1024px) {
padding-bottom: 12rem;
padding-top: 12rem;
}
}
> .wrap > .grid > .column {
align-self: auto;
flex: 0 1 auto;
order: 0;
position: relative;
width: 25%;
@media screen and (max-width: 567px) {
width: 100%;
}
@media screen and (min-width: 568px) and (max-width: 1024px) {
width: 50%;
}
@media screen and (max-width: 567px) and (orientation: portrait) {
width: 100%;
}
> .wrap-zoom {
border-radius: .3rem;
display: inline-block;
height: 25vh;
overflow: hidden;
position: relative;
transition: .3s;
@media screen and (max-width: 567px) {
height: 50vh;
}
@media screen and (min-width: 568px) and (max-width: 1023px) {
height: 33vh;
}
@media screen and (orientation: portrait) {
height: 50vw;
}
&:hover {
transform: scale(1.02);
z-index: 2;
}
&.current {
transform: scale(1.08);
}
}
> .wrap-zoom > .zoom-layer {
background: transparent;
cursor: pointer;
height: 100%;
position: absolute;
width: 100%;
}
}
.column > .wrap-zoom > .slide {
clip: rect(0 auto auto 0);
display: flex !important; // sass-lint:disable-line no-important
left: 0;
position: absolute;
top: 0;
transform: scale(.25) translate(-150%, -150vh);
@media screen and (orientation: portrait), screen and (max-width: 768px) and (orientation: landscape) {
transform: scale(.5) translate(-50%, -50%);
}
@media (max-aspect-ratio: 2 / 3) {
transform: scale(.5) translate(-50%, -50%);
}
}
& .column {
opacity: 0;
transform: scale(1.2);
transition: opacity .4s, transform .4s;
transition-delay: .2s;
}
&.in {
.column {
opacity: 1;
transform: scale(1);
}
}
}
.text-slide-number {
display: inline-block;
margin: .8rem auto;
text-align: center;
}
#webslides {
transition: filter .3s;
&.disabled,
&.zooming {
position: fixed;
width: 100%;
z-index: 0;
}
&.disabled {
/*
filter: blur(10px);
transform: scale(1.1);
*/
/* Blur makes scroll no accesible */
width: calc(100% - 10px);
}
}

View File

@@ -0,0 +1,106 @@
/* === 1.2 Animations ================
Just 5 basic animations:
.fadeIn, .fadeInUp, .zoomIn, .slideInLeft, and .slideInRight
https://github.com/daneden/animate.css */
/*-- fadeIn -- */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.fadeIn {
animation: fadeIn 1s;
}
/*-- fadeInUp -- */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translate3d(0, 100%, 0);
}
to {
opacity: 1;
transform: none;
}
}
.fadeInUp {
animation: fadeInUp 1s;
}
/*-- zoomIn -- */
@keyframes zoomIn {
from {
transform: scale3d(.3, .3, .3);
}
50% {
opacity: 1;
}
}
.zoomIn {
animation: zoomIn 1s;
}
/*-- slideInLeft -- */
@keyframes slideInLeft {
from {
transform: translate3d(-100%, 0, 0);
visibility: visible;
}
to {
transform: translate3d(0, 0, 0);
}
}
.slideInLeft {
animation: slideInLeft 1s;
animation-fill-mode: both;
}
/*-- slideInRight -- */
@keyframes slideInRight {
from {
transform: translate3d(100%, 0, 0);
visibility: visible;
}
to {
transform: translate3d(0, 0, 0);
}
}
.slideInRight {
animation: slideInRight 1s;
animation-fill-mode: both;
}
/* Animated Background (Matrix) */
@keyframes anim {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-1200px);
}
}
/* Duration */
.slow {
animation-duration: 4s;
& + & {
animation-duration: 5s;
}
}

13
src/scss/utils/_bugs.scss Normal file
View File

@@ -0,0 +1,13 @@
/*=========================================
16. SAFARI BUGS (flex-wrap)
Solution: stackoverflow.com/questions/34250282/flexbox-safari-bug-flex-wrap
=========================================== */
.flexblock:before,
.flexblock:after,
.grid:before,
.grid:after,
.cta:before,
.cta:after {
width: 0;
}

View File

@@ -0,0 +1,19 @@
/*=== Clearing === */
header,
main,
section,
aside,
footer,
.clear,
.wrap {
&:before,
&:after {
content: '';
display: table;
}
&:after {
clear: both;
}
}

View File

@@ -0,0 +1,4 @@
@mixin square($width) {
height: $width;
width: $width;
}

300
src/scss/utils/_reset.scss Normal file
View File

@@ -0,0 +1,300 @@
// sass-lint:disable no-vendor-prefixes
/*
=========================================
0. CSS Reset & Normalize
=========================================
*/
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
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,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
border: 0;
font: inherit;
font-size: 100%;
margin: 0;
padding: 0;
vertical-align: baseline;
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
main,
menu,
nav,
section,
summary {
display: block;
}
body {
line-height: 1;
}
blockquote,
q {
quotes: '' '';
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: '';
}
table {
border-collapse: collapse;
border-spacing: 0;
margin-bottom: 24px;
width: 100%;
}
html {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
audio,
canvas,
progress,
video {
display: inline-block;
vertical-align: baseline;
}
embed,
iframe,
object {
max-width: 100%;
}
audio:not([controls]) {
display: none;
height: 0;
}
[hidden],
template {
display: none;
}
ul {
list-style: square;
text-indent: inherit;
}
ol {
list-style: decimal;
}
b,
strong {
font-weight: 600;
}
a {
background-color: transparent;
}
a:active,
a:hover {
outline: 0;
}
sup,
sub {
font-size: .75em;
height: 0;
line-height: 2.2em;
position: relative;
vertical-align: baseline;
}
sup {
bottom: 1ex;
}
sub {
top: .5ex;
}
small {
font-size: .75em;
line-height: 1.72;
}
big {
font-size: 1.25em;
}
hr {
border: 0;
clear: both;
display: block;
height: 1px;
margin: 3.2rem auto;
text-align: center;
width: 100%;
}
h2 + hr,
h3 + hr {
margin-bottom: 4.8rem;
}
p + hr {
margin-bottom: 4rem;
}
dfn,
cite,
em,
i {
font-style: italic;
}
abbr,
acronym {
cursor: help;
}
mark,
ins {
padding: 0 4px;
text-decoration: none;
text-shadow: none;
}
::-moz-selection {
text-shadow: none;
}
::selection {
text-shadow: none;
}
img {
border: 0;
height: auto;
max-width: 100%;
}
img:hover {
opacity: .9;
}
svg:not(:root) {
overflow: hidden;
}
figure {
line-height: 0;
margin: 0;
position: relative;
}
optgroup {
font-weight: bold;
}
td,
th {
padding: 0;
}
dt {
font-weight: bold;
}
dd {
margin: 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,921 +0,0 @@
/*=========================================
WebSlides - Colors
=========================================== */
/* == Backgrounds == */
/* .bg-primary */
/* .bg-secondary */
/* .bg-light */
/* == General == */
/* .bg-white */
/* .bg-black */
/* .bg-black-blue */
/* .bg-brown */
/* .bg-blue */
/* .bg-gray */
/* .bg-purple */
/* .bg-red */
/* == Brands == */
/* .bg-apple */
/* .bg-facebook */
/* == Gradients == */
/* .bg-gradient-r (radial) */
/* .bg-gradient-h (horizontal) */
/* .bg-gradient-v (vertical) */
/* .bg-gradient-white */
/* .bg-gradient-gray */
/* == Transparent/Opacity Black == */
/* .bg-trans-dark */
/* .bg-trans-light */
/* .bg-trans-gradient */
/*=========================================
Base
=========================================== */
body {
color: #333;
background-color: #f7f9fb;
}
:focus {
box-shadow: 0 0 2px rgba(150, 187, 238, 1);
}
svg {
fill: currentColor;
}
[class*="bg-"] a,
[class*="bg-gradient-"] a {
color: #bce;
}
.bg-brown a {color: #c23;}
a,
.bg-white a,
.bg-light a,.bg-gradient-white a {
color: #44d;
}
a:hover {
color: #3af;
}
.flexblock li>a,[class*="bg-"] li>a,
[class*="bg-gradient-"] li>a,
article header a {
color: inherit;
}
hr {
background: rgba(0, 20, 80, 0.2);
background: radial-gradient(ellipse at center, rgba(0, 20, 80, 0.2) 0, rgba(255, 255, 255, 0) 75%);
}
hr:after {
background-color: rgba(255, 255, 255, 0.8);
color: #333;
}
bbbr,
acronym {
border-bottom: 1px dotted #333;
}
mark,
ins {
background-color: rgba(221,238,255, 0.8);
color: inherit;
}
::-moz-selection {
background-color: rgba(221,238,255, 0.8);
}
::-webkit-selection {
background-color: rgba(221,238,255, 0.8);
}
::selection {
background-color: rgba(221,238,255, 0.8);
}
pre {
border: 1px solid rgba(0, 20, 80, 0.1);
box-shadow: 0 8px 16px rgba(0,20,80,.04),0 4px 16px rgba(0,0,0,.08);
background: #fff;
}
pre:hover {
box-shadow: 0 8px 16px rgba(0,40,160,.08),0 8px 24px rgba(0,0,0,.08);
}
code,[class*="bg-"] pre {
background-color: rgba(255, 255, 255, 0.09);
}
.bg-white code{
background: rgba(0, 20, 80, 0.03);
}
/*================================================
Slides - Backgrounds <section class="bg-primary">
================================================== */
/*3 Corp Colors*/
.bg-primary {
background-color: #44d;
}
.bg-secondary {
background-color: #67d;
}
.bg-light {
background-color: #edf2f7;
}
/*General Colors*/
.bg-black {
background-color: #111;
}
.bg-black-blue {
background-color: #123;
}
.bg-blue {
background-color: #346;
}
.bg-brown {
background-color: #f8f8f9;
}
.bg-gray {
background-color: #d5d9e2;
}
.bg-green {
background-color: #077;
}
.bg-purple {
background-color: #62b;
}
.bg-red {
background-color: #c23;
}
.bg-white {
background-color: #fff;
}
[class*="bg-"] .bg-white {
text-shadow: none;
color: #333;
}
/* BG Apple Keynote*/
.bg-apple {
background: linear-gradient(to bottom, #000 0%, #1a2028 50%, #293845 100%);
}
/* BG Facebook */
.bg-facebook {
background: #3b5998;
}
/*Font Color*/
.bg-trans-dark,.bg-trans-gradient,
.bg-primary,
.bg-secondary,
.bg-blue,
.bg-green,.bg-purple,.bg-red,.bg-facebook,.bg-apple,[class*="bg-black"],[class*="bg-gradient-"] {
color: #fff;
text-shadow: 0 1px 0 #013;
}
.bg-light p {
color: #456;
}
/*.bg-white p,*/
.bg-brown p{color: #666;
}
/*Transparent/Opacity*/
.bg-trans-dark {
background: rgba(0, 0, 0, 0.8);
}
.bg-trans-light {
background: rgba(0, 0, 0, 0.2);
}
/*Covers/Longforms...*/
.bg-trans-gradient{
background: linear-gradient(to top, rgba(0,0,0,0.8) 0%,rgba(0,0,0,0) 100%);
}
/*Horizontal Gradient*/
.bg-gradient-h {
background: linear-gradient(134deg,#32b 0,#62b 100%);
}
/*Vertical Gradient*/
.bg-gradient-v {
background: linear-gradient(to top, #62b 0%, #32b 100%);
}
/*Radial Gradient*/
.bg-gradient-r {
background: radial-gradient(ellipse at center, #62b 0%, #32b 100%);
}
/*White Gradient (vertical)*/
.bg-gradient-white {
background: linear-gradient(180deg,#f2f4f6 0,#fff 100%);
color: #333;
text-shadow: none;
}
/*Gray Gradient (horizontal)*/
.bg-gradient-gray{
background: linear-gradient(90deg,#f7f9fb 0,#dee2e6 100%);
color: #333;
text-shadow: none;
}
/*Border/Frame*/
.frame {
border: .8rem solid #fff;
}
[class*="background"].frame {
border-width: .2rem;
}
/*Layer/Box Shadow*/
.shadow,.pre {
position: relative;
}
.shadow:before,.shadow:after {
box-shadow: 0 16px 24px rgba(0, 20, 80, 0.3);
}
/*============================
TYPOGRAPHY
============================== */
/* -- Horizontal separator -- */
.text-separator:before {
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);
}
img[class*="text-pull-"],figure[class*="text-pull-"] {
border-top: none;
}
/* -- Context -- */
[class*="bg-"] .text-context:before {
background-color: #fff;
}
.text-context:before,.bg-white .text-context:before{
background-color: rgba(0, 20, 80, 0.2);
}
/* -- Text shadow -- */
.text-shadow {
text-shadow: 0 0 40px rgba(0, 0, 0, 0.5);
}
/* -- time, ampersands, prepositions (for, of...), symbols... -- */
[class*="card-"] time,
h1 span {
color: #abd;
}
/* -- <pre> comment -- */
.code-comment {
color: rgba(70, 170, 130, 0.9);
text-shadow: none;
}
/*=========================================
Header/Nav
=========================================== */
header[role=banner] {
background-color: #fff;
}
.logo a {
color: inherit;
}
nav[role=navigation] li a {
background-color: rgba(50, 50, 50, .9);
}
nav[role=navigation] li a:hover {
background-color: rgba(50, 50, 50, .7);
}
nav[role=navigation] li a,
nav[role=navigation] li a:hover {
color: #fff;
}
nav[role=navigation] li.active a {
background-color: #555;
color: #fff;
}
nav li.twitter a:hover {
background-color: #1da1f3;
}
nav li.facebook a:hover {
background-color: #3b5998;
}
nav li.linkedin a:hover {
background-color: #1683bb;
}
nav li.dribbble a:hover {
background-color: #ea4c89;
}
nav li.github a:hover {
background-color: #60b044;
}
nav li.email a:hover {
background: #dd4b39;
}
/*===================================================
.flexblock li hover/active
===================================================== */
.flexblock li.active a,
.metrics li:hover,
.specs li:hover,.reasons li:hover {
background-color: rgba(0, 20, 80, 0.03);
}
/*=========================================
Features & Clients List
=========================================== */
.features li,.clients li {
background-color: rgba(255, 255, 255, 0.9);
}
[class*="bg-"] .features li,
[class*="bg-"] .clients li {
background-color: rgba(255, 255, 255, 0.1);
}
.features li:hover,.clients li:hover {
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;}*/
/*============================
.flexblock with border
============================== */
.border {
border-right: 1px solid rgba(0, 20, 80, 0.1);
border-bottom: 1px solid rgba(0, 20, 80, 0.1);
}
.border li {
border-top: 1px solid rgba(0, 20, 80, 0.1);
border-left: 1px solid rgba(0, 20, 80, 0.1);
}
.flexblock.border li li {
border: none;
}
/*===========================================
flexblock.steps
============================================= */
.steps li:nth-child(1) {
background-color: #e8eef7;
}
.steps li:nth-child(2) {
background-color: #dde5f3;
}
.steps li:nth-child(3) {
background-color: #cdd8ec;
}
.steps li:nth-child(4) {
background-color: #bbcdec;
}
.process {
border-top: 15px solid transparent;
border-bottom: 15px solid transparent;
}
.steps li:hover,
.steps.blink li:hover>a {
background-color: #b8cef7;
}
@media (min-width: 1024px) {
.process.step-2 {
border-left-color: #e8eef7;
}
.process.step-3 {
border-left-color: #dde5f3;
}
.process.step-4 {
border-left-color: #cdd8ec;
}
.steps li:hover + li [class*="step-"] {
border-left-color: #b8cef7;
}
}
/*=========================================================
Items: You can use for settings, drag&drop, close/delete...
=========================================================== */
.specs li:after {
background: linear-gradient(to right, rgba(0, 20, 80, 0) 0%, rgba(0, 20, 80, 0.2) 50%, rgba(0, 20, 80, 0) 100%);
}
.specs li:last-child:after {
background: none;
}
/*.specs li {background: rgba(255,255,255,0.2);}*/
/*=========================================================
Why/Steps/Motivation/Reasons - Decimal/Numbers
=========================================================== */
.reasons li:after {
background: linear-gradient(to right, rgba(0, 20, 80, 0) 0%, rgba(0, 20, 80, 0.2) 50%, rgba(0, 20, 80, 0) 100%);
}
.reasons li:last-child:after {
background: none;
}
/*=========================================
Overlays
=========================================== */
.overlay {
background-color: rgba(0, 0, 0, 0.2);
/*background-color: rgba(255,255,255 , 0.9);*/
/*border: 3px double #fff;*/
}
li:hover .overlay {
background-color: rgba(0, 0, 0, 0.1);
}
.overlay,
.overlay a {
color: #fff;
text-shadow: 0 1px 0 #111;
}
/*=========================================
Gallery li+.overlay+image
=========================================== */
.gallery li {
background-color: rgba(0, 20, 80, 0.06);
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 4px 8px rgba(0, 0, 0, 0.03);
}
.gallery li figcaption {
background-color: #fff;
}
.flexblock.gallery li:hover {
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);
}
.gallery li a {
color: #333;
text-shadow: none;
}
.flesblock.gallery li a footer{color: #aaa;}
/*Arrow */
.gallery li figcaption:before {
border: .8rem solid black;
border-color: transparent transparent #fff #fff;
/*box-shadow: -3px 3px 3px 0 rgba(0, 0, 0, 0.4);*/
}
/*=========================================
Plans / Pricing
=========================================== */
.plans>li div,
.flexblock.plans li:hover div {
background-color: #fff;
}
.plans>li:hover,
.plans>li:nth-child(2) {
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1), 0 8px 16px rgba(0, 0, 0, 0.1);
}
.plans:hover li:nth-child(2):not(:hover) {
box-shadow: none;
}
.plans li h2 {
background-color: rgba(0, 20, 80, 0.5);
color: #fff;
}
.plans ul li {
border-bottom: 1px solid rgba(0, 20, 80, 0.1);
}
.plans ul li:last-child {
border-bottom: none;
}
.plans>li>a {
color: inherit;
}
.plans>li>a {
color: #333;
text-shadow: none;
}
/*============================
Activity/CV/Timeline/News
============================== */
.activity li {
border-top: .1rem solid rgba(0, 20, 80, 0.1);
}
.activity li:hover {
background-color: rgba(0, 20, 80, 0.02);
}
/*=========================================
Resume/Work/CV/Portfolio
=========================================== */
.work-label,
.work li a {
border-bottom: 1px solid rgba(0, 20, 80, 0.1);
}
.work li:nth-child(odd)>a {
background-color: rgba(0, 20, 80, 0.03);
}
.work li a:hover {
background-color: rgba(0, 20, 80, 0.04);
}
/*===========================================
Clients / Services / Logos...
============================================= */
.clients.border figcaption {border-top:1px solid rgba(0,20,80,0.1);
}
/*.clients>li {
background: rgba(255, 255, 255, 0.8);
}
*/
/*====================
LOGOS
====================== */
img.blacklogo {
background: none;
/* --- Images (black logo/image) --- */
-webkit-filter: grayscale(100%) brightness(10%) contrast(100%);
filter: grayscale(100%) brightness(10%) contrast(100%);
}
/* --- Images (gray logo/image) --- */
img.graylogo {
-webkit-filter: grayscale(100%) brightness(10%) contrast(10%);
filter: grayscale(100%) brightness(10%) contrast(10%);
}
/* --- Images (white Logo/Image) --- */
img.whitelogo {
-webkit-filter: brightness(0) invert(1);
filter: brightness(0) invert(1);
}
/* --- Logo/Images Hover --- */
li:hover img.blacklogo,
li:hover img.graylogo,
img.blacklogo:hover,img.graylogo:hover {
background: none;
/*Images - Original Color*/
filter: grayscale(0%);
-webkit-filter: grayscale(0%);
filter: none;
transition: all 0.6s ease;
}
/*=========================================================
Cards
=========================================================== */
[class*="card-"]>a {
color: inherit;
}
/* --- card ul specs --- */
.description>li {
border-bottom: 1px solid rgba(0, 20, 80, 0.1);
}
.description>li:last-child {
border-bottom: none;
}
/*== Figure Background === */
[class*="card-"][class*="bg-"] figure {
background-color: rgba(0, 20, 80, 0.06);
}
/*== Ficaption Cards === */
[class*="card"] figcaption,
[class*="card"] figcaption a {
color: #fff;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.2) 100%);
}
@media (min-width: 768px) {
/*===CTA (Call to Action - Numbers, Price, Promo...) ===== */
.cta .benefit {
border-left-width: 1px;
border-style: solid;
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%;
}
}
/*=========================================
Tables
=========================================== */
table td,
th,
thead {
border: 1px solid rgba(0, 0, 0, 0.5);
}
thead {
background-color: rgba(0, 0, 0, 0.3);
}
tr:nth-child(even)>td {
background: rgba(0, 0, 0, 0.1);
}
tr>td {
border-top: 1px solid rgba(0, 0, 0, 0.5);
}
td:hover,
tr:nth-child(even)>td:hover {
background-color: rgba(255, 255, 255, 0.5);
}
/*============================
Browser (Screenshots)
============================== */
.browser {
border: 1px solid rgba(0, 20, 80, 0.1);
}
.browser:hover {
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1), 0 8px 16px rgba(0, 0, 0, 0.1);
}
/*=== Topbar === */
.browser:before {
background-color: rgba(0, 20, 80, 0.1);
color: rgba(255, 255, 255, 0.9);
border-bottom: 1px solid rgba(0, 20, 80, 0.2);
}
.browser:hover:before {
background-color: rgba(0, 20, 80, 0.12);
color: #fff;
}
/*=========================================
Forms
=========================================== */
input,
textarea {
background-color: #fafbfc;
}
input:focus,
textarea:focus {
background-color: #fff;
box-shadow: 0 0 5px rgba(81, 203, 238, 1);
}
input:focus::-moz-placeholder {
color: #ddd;
}
input:focus::-webkit-input-placeholder {
color: #ddd;
}
a.button,[class*="badge-"]
button[type="submit"],
input {
box-shadow: 0px 10px 16px -8px rgba(0, 20, 80, 0.3);
}
button,
input,
select,
textarea,
button[type="submit"],
input[type="submit"],
.button,.button:hover,
button[type="submit"]:hover,
input[type="submit"]:hover
{
border: 1px solid #44d;
}
button[type="submit"],
input[type="submit"],
.button,.button:hover,button[type="submit"]:hover,input[type="submit"]:hover {
color: #fff;
background-color: #44d;
text-shadow: 0 1px 0 #123;
}
.button:active,button[type="submit"]:active,input[type="submit"]:active {
background-color: #17d;
}
.ghost,.ghost:hover {background: none;color: inherit;text-shadow: none;}
.bg-primary select,
.bg-primary textarea,
.bg-primary .button,
.bg-primary button,.bg-primary button:hover,
.bg-primary input,
[class*="bg-gradient-"] .button,[class*="bg-"] a.button.ghost
{
border-color: #fff;
}
[class*="bg-"] a.button {
color: #fff;
}
.bg-white a.button.ghost,.bg-gradient-white a.button.ghost {color: #333;border: 1px solid #44d;}
:disabled,
button:disabled:hover {
background-color: #eee;
border-color: #eee;
color: #ccc;
}
fieldset {
border: 1px solid #44d;
background-color: rgba(0, 20, 80, 0.2)
}
legend {
background-color: rgba(0, 0, 0, 0.6);
color: #fff;
}
/* Inputs/Buttons - hover */
input:hover,
select:hover {
box-shadow: 0 0 8px rgba(0, 0, 0, 0.3);
}
/* App Store Badges */
[class*="badge-"] {
border: 1px solid #345;
background-color: #000;
/* Transparent Button */
/* background: none;*/
}
form .flexblock li:hover {
background-color: rgba(0, 0, 0, 0.05);
}
/*============================
Table of Contents
============================== */
.toc,
.toc ol>li:before,
.chapter {
background-color: #f7f9fb;
}
.toc li .toc-page:before {
border-bottom: 1px dotted rgba(0, 0, 0, 0.9);
}
/*============================
Slides (Counter/Arrows)
============================== */
/*#navigation:hover {
background-color: rgba(0, 0, 0, 0.03);
}
*/
#counter,
#navigation a {
color: #abc;
}
#webslides:hover #navigation a:hover {
color: #fff;
background-color: rgba(0, 0, 0, 0.9);
}
/*============================
Footer
============================== */
footer[role=contentinfo] {
background-color: #fff;
}
/*footer:hover {
background-color:rgba(255,255,255 , 0.3);
}
*/

3791
static/css/webslides.css Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,40 +0,0 @@
import test from 'ava';
import DOM from '../src/js/utils/dom';
test('DOM.createNode', t => {
const div = DOM.createNode('div', 'my-id');
t.is(div.tagName, 'DIV');
t.is(div.id, 'my-id');
t.is(div.innerHTML, '');
});
test('DOM.once', t => {
const div = DOM.createNode('div');
DOM.once(div, 'click', () => div.classList.toggle('ok'));
div.click();
t.is(div.className, 'ok');
div.click();
t.is(div.className, 'ok');
});
test('DOM.hide', t => {
const div = DOM.createNode('div');
DOM.hide(div);
t.is(div.style.display, 'none');
});
test('DOM.show', t => {
const div = DOM.createNode('div');
DOM.hide(div);
DOM.show(div);
t.is(div.style.display, '');
});
test('DOM.fireEvent', t => {
const div = DOM.createNode('div');
div.addEventListener('toggle-class', () => div.classList.toggle('ok'));
DOM.fireEvent(div, 'toggle-class');
t.is(div.className, 'ok');
DOM.fireEvent(div, 'toggle-class');
t.is(div.className, '');
});

View File

@@ -1,2 +0,0 @@
import browserEnv from 'browser-env';
browserEnv();

152
test/modules/slide.test.js Normal file
View File

@@ -0,0 +1,152 @@
import Slide from '../../src/js/modules/slide';
describe('Slide module', () => {
test('Candidate', () => {
const valid = document.createElement('section');
const invalid = document.createElement('p');
expect(Slide.isCandidate(valid)).toBe(true);
expect(Slide.isCandidate(invalid)).toBe(false);
});
describe('Instance behaviour', () => {
let ws;
let slides;
beforeEach(() => {
const template =
'<section><div class="content">Content</div></section>'
.repeat(5);
document.body.innerHTML = `<div id="webslides">${template}</div>`;
const el = document.getElementById('webslides');
slides = [];
el.querySelectorAll('section').forEach((el, i) => {
slides.push(new Slide(el, i));
});
ws = {
el,
slides
};
});
afterEach(() => {
document.body.innerHTML = '';
});
test('Slides should have some properties', () => {
const slide = ws.slides[0];
expect(slide.el).toBeInstanceOf(Element);
expect(slide.el.id).toBe('section-1');
expect(slide.parent).toBeInstanceOf(Element);
expect(slide.parent.id).toBe('webslides');
expect(slide.i).toBe(0);
});
test('Slides should get a slide class and be hidden', () => {
const slide = ws.slides[0];
expect(slide.el.classList.contains('slide')).toBe(true);
expect(slide.el.style.display).toBe('none');
});
test('Show/hide', () => {
const slide = ws.slides[0];
slide.show();
expect(slide.el.style.display).not.toBe('none');
expect(slide.el.classList.contains('current')).toBe(true);
slide.hide();
expect(slide.el.style.display).toBe('none');
expect(slide.el.classList.contains('current')).not.toBe(true);
});
test('Events', () => {
const slide = ws.slides[0];
const leave = jest.fn();
const enter = jest.fn();
const enable = jest.fn();
const disable = jest.fn();
const show = jest.fn();
slide.el.addEventListener('dom:leave', leave);
slide.el.addEventListener('dom:enter', enter);
slide.el.addEventListener('slide:enable', enable);
slide.el.addEventListener('slide:disable', disable);
slide.el.addEventListener('slide:show', show);
expect(enter).not.toHaveBeenCalled();
expect(leave).not.toHaveBeenCalled();
expect(enable).not.toHaveBeenCalled();
expect(disable).not.toHaveBeenCalled();
expect(show).not.toHaveBeenCalled();
slide.enable();
expect(enter).not.toHaveBeenCalled();
expect(leave).not.toHaveBeenCalled();
expect(enable).toHaveBeenCalledTimes(1);
expect(disable).not.toHaveBeenCalled();
expect(show).not.toHaveBeenCalled();
enable.mockClear();
slide.disable();
expect(enter).not.toHaveBeenCalled();
expect(leave).not.toHaveBeenCalled();
expect(enable).not.toHaveBeenCalled();
expect(disable).toHaveBeenCalledTimes(1);
expect(show).not.toHaveBeenCalled();
disable.mockClear();
slide.moveAfterLast();
expect(enter).toHaveBeenCalledTimes(1);
expect(leave).toHaveBeenCalledTimes(1);
expect(enable).not.toHaveBeenCalled();
expect(disable).not.toHaveBeenCalled();
expect(show).not.toHaveBeenCalled();
enter.mockClear();
leave.mockClear();
slide.moveBeforeFirst();
expect(enter).toHaveBeenCalledTimes(1);
expect(leave).toHaveBeenCalledTimes(1);
expect(enable).not.toHaveBeenCalled();
expect(disable).not.toHaveBeenCalled();
expect(show).not.toHaveBeenCalled();
enter.mockClear();
leave.mockClear();
slide.show();
expect(show).toHaveBeenCalled();
});
test('Move', () => {
const wsEl = document.getElementById('webslides');
const slide = ws.slides[0];
expect(wsEl.lastChild).not.toBe(slide.el);
slide.moveAfterLast();
expect(wsEl.lastChild).toBe(slide.el);
expect(wsEl.firstChild).not.toBe(slide.el);
slide.moveBeforeFirst();
expect(wsEl.firstChild).toBe(slide.el);
});
test('Get section from el', () => {
const wsEl = document.getElementById('webslides');
const el = ws.slides[3].el.firstChild;
const found = Slide.getSectionFromEl(el);
expect(found.section.id).toBe('section-4');
expect(found.i).toBe(4);
const notFound = Slide.getSectionFromEl(wsEl);
expect(notFound.section).toBeNull();
expect(notFound.i).toBeNull();
});
});
});

View File

@@ -0,0 +1,411 @@
import WebSlides from '../../src/js/modules/webslides';
import Slide from '../../src/js/modules/slide';
import DOM from '../../src/js/utils/dom';
jest.useFakeTimers();
let ws;
let webslides;
beforeEach(() => {
const slides =
'<section class="slide"><div class="content">Content</section>'.repeat(20);
document.body.innerHTML =
`<div id="webslides">${slides}<div id="other"></div></div>`;
ws = document.getElementById('webslides');
webslides = new WebSlides();
});
afterEach(() => {
document.body.innerHTML = '';
location.hash = '';
});
test('Should throw if no element is found with webslides id', () => {
document.body.innerHTML = '';
expect(() => {
ws.setAttribute('id', '');
new WebSlides();
}).toThrow('Couldn\'t find the webslides container!');
});
test('Should have correct properties', () => {
expect(webslides.isMoving).toBe(false);
expect(webslides.slides.length).toBe(20);
expect(webslides.currentSlideI_).toBe(0);
expect(webslides.currentSlide_).toBe(webslides.slides[0]);
expect(webslides.maxSlide_).toBe(20);
expect(webslides.isVertical).toBe(false);
expect(webslides.initialised).toBe(true);
expect(webslides.slides[0]).toBeInstanceOf(Slide);
// Plugins
expect(webslides.plugins.autoslide).toBeDefined();
expect(webslides.plugins.clickNav).toBeDefined();
expect(webslides.plugins.grid).toBeDefined();
expect(webslides.plugins.hash).toBeDefined();
expect(webslides.plugins.keyboard).toBeDefined();
expect(webslides.plugins.nav).toBeDefined();
expect(webslides.plugins.scroll).toBeDefined();
expect(webslides.plugins.touch).toBeDefined();
expect(webslides.plugins.video).toBeDefined();
expect(webslides.plugins.youtube).toBeDefined();
expect(webslides.plugins.zoom).toBeDefined();
// Options
expect(webslides.options.autoslide).toBe(false);
expect(webslides.options.changeOnClick).toBe(false);
expect(webslides.options.loop).toBe(true);
expect(webslides.options.minWheelDelta).toBe(40);
expect(webslides.options.navigateOnScroll).toBe(true);
expect(webslides.options.scrollWait).toBe(450);
expect(webslides.options.slideOffset).toBe(50);
});
test('Should be able to define vertical WS', () => {
ws.classList.add('vertical');
webslides = new WebSlides();
expect(webslides.isVertical).toBe(true);
});
test('Should remove all elements that are not sections', () => {
expect(document.getElementById('other')).toBeNull();
});
test('Ready', () => {
// Already initialised
expect(document.documentElement.classList.contains('ws-ready')).toBe(true);
document.documentElement.classList.remove('ws-ready');
const listener = jest.fn();
ws.addEventListener('ws:init', listener);
webslides.initialised = false;
webslides.onInit_();
expect(listener).toHaveBeenCalled();
expect(document.documentElement.classList.contains('ws-ready')).toBe(true);
expect(webslides.initialised).toBe(true);
});
test('Should be possible to init with a different slide', () => {
location.hash = '#slide=4';
webslides = new WebSlides();
expect(webslides.currentSlideI_).toBe(3);
});
describe('Go to slide', () => {
beforeEach(() => {
jest.spyOn(webslides, 'scrollTransitionToSlide_');
jest.spyOn(webslides, 'transitionToSlide_');
});
test('Shouldn\'t allow to go to invalid indexes', () => {
webslides.goToSlide(-4);
webslides.goToSlide(null);
webslides.goToSlide(99);
expect(webslides.scrollTransitionToSlide_).not.toHaveBeenCalled();
expect(webslides.transitionToSlide_).not.toHaveBeenCalled();
});
test('Shouldn\'t allow to move if already moving', () => {
webslides.isMoving = true;
webslides.goToSlide(2);
expect(webslides.scrollTransitionToSlide_).not.toHaveBeenCalled();
expect(webslides.transitionToSlide_).not.toHaveBeenCalled();
});
test('Shouldn\'t allow to move if going to same slide', () => {
webslides.goToSlide(0);
expect(webslides.scrollTransitionToSlide_).not.toHaveBeenCalled();
expect(webslides.transitionToSlide_).not.toHaveBeenCalled();
});
test('Shouldn\'t use Scroll if first slide', () => {
webslides.isVertical = true;
webslides.currentSlide_ = null;
webslides.goToSlide(1);
expect(webslides.scrollTransitionToSlide_).not.toHaveBeenCalled();
expect(webslides.transitionToSlide_).toHaveBeenCalled();
});
test('Shouldn\'t use Scroll if not vertical', () => {
webslides.isVertical = false;
webslides.goToSlide(1);
expect(webslides.scrollTransitionToSlide_).not.toHaveBeenCalled();
expect(webslides.transitionToSlide_).toHaveBeenCalled();
});
test('Shouldn\'t use Scroll if no touch or not enabled', () => {
webslides.plugins.touch = null;
webslides.goToSlide(1);
expect(webslides.scrollTransitionToSlide_).not.toHaveBeenCalled();
expect(webslides.transitionToSlide_).toHaveBeenCalled();
webslides.transitionToSlide_.mockClear();
webslides.plugins.touch = {
isEnabled: false
};
webslides.goToSlide(2);
expect(webslides.scrollTransitionToSlide_).not.toHaveBeenCalled();
expect(webslides.transitionToSlide_).toHaveBeenCalled();
});
test('Forward should be true if moving ahead or forced', () => {
const getIsMovingForward = () =>
webslides.transitionToSlide_.mock.calls[0][0];
webslides.goToSlide(2);
expect(getIsMovingForward()).toBe(true);
webslides.transitionToSlide_.mockClear();
// Going back
webslides.goToSlide(1);
expect(getIsMovingForward()).toBe(false);
webslides.transitionToSlide_.mockClear();
// Going forward but forced
webslides.goToSlide(3, false);
expect(getIsMovingForward()).toBe(false);
webslides.transitionToSlide_.mockClear();
});
test('Should pass correct arguments to transition to slide', () => {
webslides.goToSlide(2);
const args = webslides.transitionToSlide_.mock.calls[0];
expect(args[1]).toBeInstanceOf(Slide);
expect(args[1]).toBe(webslides.slides[2]);
expect(args[2]).toBe(webslides.onSlideChange_);
});
test('Should pass correct arguments to scroll to slide', () => {
webslides.isVertical = true;
webslides.goToSlide(2);
const args = webslides.scrollTransitionToSlide_.mock.calls[0];
expect(args[1]).toBeInstanceOf(Slide);
expect(args[1]).toBe(webslides.slides[2]);
expect(args[2]).toBe(webslides.onSlideChange_);
});
test('After move', () => {
webslides.isVertical = true;
const mock = jest.fn();
const currentSlide = webslides.currentSlide_;
webslides.el.addEventListener('ws:slide-change', mock);
webslides.goToSlide(1);
expect(webslides.isMoving).toBe(true);
jest.runAllTimers();
expect(webslides.isMoving).toBe(false);
expect(webslides.currentSlide_).not.toBe(currentSlide);
expect(webslides.currentSlide_).toBe(webslides.slides[1]);
expect(webslides.currentSlideI_).toBe(1);
expect(currentSlide.el.style.display).toBe('none');
const mockEvent = mock.mock.calls[0][0].detail;
expect(mockEvent.slides).toBe(webslides.maxSlide_);
expect(mockEvent.currentSlide0).toBe(1);
expect(mockEvent.currentSlide).toBe(2);
});
});
describe('Go next/prev', () => {
beforeEach(() => {
jest.spyOn(webslides, 'goToSlide');
});
test('Go next should go to the next slide', () => {
webslides.goNext();
expect(webslides.goToSlide).toHaveBeenCalledWith(1, true);
});
test('Go prev should go to the previous slide', () => {
webslides.currentSlideI_ = 2;
webslides.goPrev();
expect(webslides.goToSlide).toHaveBeenCalledWith(1, false);
});
test('Should not be possible to move if loop is disabled and on edge', () => {
webslides.options.loop = false;
webslides.goPrev();
expect(webslides.goToSlide).not.toHaveBeenCalled();
webslides.currentSlideI_ = webslides.maxSlide_;
webslides.goNext();
expect(webslides.goToSlide).not.toHaveBeenCalled();
});
test('It should loop correctly', () => {
webslides.currentSlideI_ = webslides.maxSlide_ - 1;
webslides.goNext();
expect(webslides.goToSlide).toHaveBeenCalledWith(0, true);
webslides.goPrev();
expect(webslides.goToSlide).toHaveBeenCalledWith(19, false);
});
});
describe('Scroll to', () => {
test('Overflow should be removed and resetted', () => {
webslides.scrollTransitionToSlide_(true, webslides.slides[1], () => {});
expect(webslides.el.style.overflow).toBe('hidden');
jest.runAllTimers();
expect(webslides.el.style.overflow).not.toBe('hidden');
});
test('Should move slide if not moving forward', () => {
const getHTML = () => webslides.el.innerHTML;
expect(getHTML().indexOf('section-1"'))
.toBeLessThan(getHTML().indexOf('section-20"'));
webslides.scrollTransitionToSlide_(false, webslides.slides[19], () => {});
expect(getHTML().indexOf('section-20"'))
.toBeLessThan(getHTML().indexOf('section-1"'));
});
test('Should not move slide if moving forward', () => {
const getHTML = () => webslides.el.innerHTML;
expect(getHTML().indexOf('section-1"'))
.toBeLessThan(getHTML().indexOf('section-2"'));
webslides.scrollTransitionToSlide_(true, webslides.slides[1], () => {});
expect(getHTML().indexOf('section-1"'))
.toBeLessThan(getHTML().indexOf('section-2"'));
});
test('Should call the callback once finished with the next slide', () => {
const cb = jest.fn();
webslides.scrollTransitionToSlide_(true, webslides.slides[1], cb);
expect(cb).not.toHaveBeenCalled();
jest.runAllTimers();
expect(cb).toHaveBeenCalledWith(webslides.slides[1]);
});
});
describe('Transition to', () => {
test('Should move slide if not moving forward', () => {
const getHTML = () => webslides.el.innerHTML;
expect(getHTML().indexOf('section-1"'))
.toBeLessThan(getHTML().indexOf('section-20"'));
webslides.transitionToSlide_(false, webslides.slides[19], () => {});
expect(getHTML().indexOf('section-20"'))
.toBeLessThan(getHTML().indexOf('section-1"'));
});
test('Should move current slide to last if moving forward', () => {
const getHTML = () => webslides.el.innerHTML;
expect(getHTML().indexOf('section-1'))
.toBeLessThan(getHTML().indexOf('section-2'));
webslides.transitionToSlide_(true, webslides.slides[1], () => {});
expect(getHTML().indexOf('section-1"'))
.toBeGreaterThan(getHTML().indexOf('section-20"'));
});
test('Should slideInRight if touch and moving forward', () => {
const callback = jest.fn();
const nextSlideEl = webslides.slides[19].el;
webslides.initialised = true;
webslides.plugins.touch = {
isEnabled: true
};
webslides.transitionToSlide_(true, webslides.slides[19], callback);
expect(nextSlideEl.classList.contains('slideInRight'))
.toBe(true);
expect(callback).not.toBeCalled();
DOM.fireEvent(nextSlideEl, 'animationend');
expect(callback).toHaveBeenCalledWith(webslides.slides[19]);
expect(nextSlideEl.classList.contains('slideInRight'))
.toBe(false);
});
test('Should slideInLeft if touch and not moving forward', () => {
const callback = jest.fn();
const nextSlideEl = webslides.slides[1].el;
webslides.initialised = true;
webslides.plugins.touch = {
isEnabled: true
};
webslides.transitionToSlide_(false, webslides.slides[1], callback);
expect(nextSlideEl.classList.contains('slideInLeft'))
.toBe(true);
expect(callback).not.toBeCalled();
DOM.fireEvent(nextSlideEl, 'animationend');
expect(callback).toHaveBeenCalledWith(webslides.slides[1]);
expect(nextSlideEl.classList.contains('slideInLeft'))
.toBe(false);
});
});
test('Enable/Disable', () => {
expect(webslides.isDisabled()).toBe(false);
expect(webslides.el.classList.contains('disabled')).toBe(false);
webslides.disable();
expect(webslides.el.classList.contains('disabled')).toBe(true);
expect(webslides.isDisabled()).toBe(true);
webslides.enable();
expect(webslides.isDisabled()).toBe(false);
expect(webslides.el.classList.contains('disabled')).toBe(false);
});
test('Fullscreen', () => {
// Mocking FullScreen API
document.fullscreen = false;
document.documentElement.requestFullscreen = jest.fn();
document.exitFullScreen = jest.fn();
expect(document.documentElement.requestFullscreen).not.toHaveBeenCalled();
webslides.fullscreen();
expect(document.documentElement.requestFullscreen).toHaveBeenCalled();
document.fullscreen = true;
expect(document.exitFullScreen).not.toHaveBeenCalled();
webslides.fullscreen();
expect(document.exitFullScreen).toHaveBeenCalled();
});
test('Zoom', () => {
webslides.plugins.zoom = {
toggleZoom: jest.fn()
};
expect(webslides.plugins.zoom.toggleZoom).not.toHaveBeenCalled();
webslides.toggleZoom();
expect(webslides.plugins.zoom.toggleZoom).toHaveBeenCalled();
});
test('Plugin register', () => {
const cto = jest.fn();
const Mock = function() {
cto();
};
WebSlides.registerPlugin('mock', Mock);
webslides = new WebSlides();
expect(cto).toHaveBeenCalled();
expect(webslides.plugins.mock).toBeDefined();
});

View File

@@ -0,0 +1,43 @@
import DOM from '../../src/js/utils/dom';
import AutoSlide from '../../src/js/plugins/autoslide';
jest.useFakeTimers();
beforeAll(() => {
document.body.innerHTML =
`<div id="webslides"></div><input id="focusable" />`;
});
test('AutoSlide plugin', () => {
const next = jest.fn();
const ws = document.getElementById('webslides');
const webslides = {
options: {
autoslide: 100
},
goNext: next,
el: ws
};
expect(next).not.toBeCalled();
new AutoSlide(webslides);
DOM.fireEvent(ws, 'ws:init');
// Wait until next execution
jest.runTimersToTime(101);
expect(next.mock.calls.length).toBe(1);
// Wait until next execution
jest.runTimersToTime(101);
expect(next.mock.calls.length).toBe(2);
// Pause on focus
document.getElementById('focusable').focus();
DOM.fireEvent(document.body, 'focus');
jest.runTimersToTime(101);
expect(next.mock.calls.length).toBe(2);
});

View File

@@ -0,0 +1,26 @@
import DOM from '../../src/js/utils/dom';
import ClickNav from '../../src/js/plugins/click-nav';
beforeAll(() => {
document.body.innerHTML =
`<div id="webslides" data-test="test"><p>Text</p></div>`;
});
test('Click nav plugin', () => {
const next = jest.fn();
const ws = document.getElementById('webslides');
const webslides = {
options: {
changeOnClick: true
},
goNext: next,
el: ws
};
expect(next).not.toBeCalled();
new ClickNav(webslides);
DOM.fireEvent(ws, 'click');
expect(next.mock.calls.length).toBe(1);
});

View File

@@ -0,0 +1,91 @@
import Keyboard from '../../src/js/plugins/keyboard';
import Keys from '../../src/js/utils/keys';
// @TODO: Check to do this with simulant
const simulateKeyEvent = (el, code, extra) => {
const config = Object.assign({
bubbles: true,
cancelableCode: true,
which: code,
shiftKey: false}, extra);
const evt = new KeyboardEvent('keydown', config);
el.dispatchEvent(evt);
};
beforeAll(() => {
document.body.innerHTML = `<div id="webslides" data-test="test">
<p>Text</p>
</div>
<input id="focusable" />`;
});
test('Keyboard plugin', () => {
const goto = jest.fn();
const next = jest.fn();
const prev = jest.fn();
const fullscreen = jest.fn();
const ws = document.getElementById('webslides');
let disabled = true;
const webslides = {
goToSlide: goto,
goNext: next,
goPrev: prev,
isVertical: false,
fullscreen: fullscreen,
isDisabled: () => disabled,
el: ws
};
const key = new Keyboard(webslides);
expect(goto).not.toBeCalled();
expect(next).not.toBeCalled();
expect(prev).not.toBeCalled();
simulateKeyEvent(document, Keys.AV_PAGE);
expect(next.mock.calls.length).toBe(0);
disabled = false;
simulateKeyEvent(document, Keys.AV_PAGE);
expect(next.mock.calls.length).toBe(1);
simulateKeyEvent(document, Keys.SPACE);
expect(next.mock.calls.length).toBe(2);
// Shift + Space
simulateKeyEvent(document, Keys.SPACE, {shiftKey: true});
expect(next.mock.calls.length).toBe(2);
expect(prev.mock.calls.length).toBe(1);
simulateKeyEvent(document, Keys.RE_PAGE);
expect(prev.mock.calls.length).toBe(2);
// Home - End
simulateKeyEvent(document, Keys.HOME);
expect(goto.mock.calls.length).toBe(1);
simulateKeyEvent(document, Keys.END);
expect(goto.mock.calls.length).toBe(2);
// Arrow keys, only left right should increase
simulateKeyEvent(document, Keys.DOWN);
simulateKeyEvent(document, Keys.UP);
simulateKeyEvent(document, Keys.LEFT);
simulateKeyEvent(document, Keys.RIGHT);
expect(prev.mock.calls.length).toBe(3);
expect(next.mock.calls.length).toBe(3);
// Arrow keys, only up down should increase
key.ws_.isVertical = true;
simulateKeyEvent(document, Keys.DOWN);
simulateKeyEvent(document, Keys.UP);
simulateKeyEvent(document, Keys.LEFT);
simulateKeyEvent(document, Keys.RIGHT);
expect(prev.mock.calls.length).toBe(4);
expect(next.mock.calls.length).toBe(4);
// F, only trigger on when alone
simulateKeyEvent(document, Keys.F);
simulateKeyEvent(document, Keys.F, {ctrlKey: true});
simulateKeyEvent(document, Keys.F, {metaKey: true});
expect(fullscreen.mock.calls.length).toBe(1);
});

View File

@@ -0,0 +1,65 @@
import DOM from '../../src/js/utils/dom';
import Navigation from '../../src/js/plugins/navigation';
beforeAll(() => {
document.body.innerHTML = `<div id="webslides"></div>`;
});
test('Navigation plugin', () => {
const ws = document.getElementById('webslides');
const zoom = jest.fn();
const next = jest.fn();
const prev = jest.fn();
const webslides = {
el: ws,
goNext: next,
goPrev: prev,
toggleZoom: zoom,
options: {showIndex: true}
};
const fakeArrow = Navigation.createArrow('arrow', 'Test');
expect(fakeArrow.tagName).toBe('A');
expect(fakeArrow.title).toBe('Arrow Keys');
expect(fakeArrow.id).toBe('arrow');
expect(fakeArrow.textContent).toBe('Test');
const fakeCounter = Navigation.createCounter('counter', webslides);
expect(fakeCounter.tagName).toBe('SPAN');
expect(fakeCounter.childNodes.length).toBe(1);
expect(fakeCounter.childNodes[0].tagName).toBe('A');
expect(fakeCounter.childNodes[0].href).toBe('http://localhost/#');
expect(fakeCounter.childNodes[0].title).toBe('View all slides');
new Navigation(webslides);
const navElem = ws.querySelector('#navigation');
const counter = navElem.querySelector('#counter');
const nextElem = navElem.querySelector('#next');
const prevElem = navElem.querySelector('#previous');
expect(navElem).not.toBe(null);
expect(counter).not.toBe(null);
expect(nextElem).not.toBe(null);
expect(prevElem).not.toBe(null);
DOM.fireEvent(ws, 'ws:slide-change', {
slides: 3,
currentSlide0: 1,
currentSlide: 2
});
expect(counter.textContent).toBe('2 / 3');
expect(next.mock.calls.length).toBe(0);
expect(prev.mock.calls.length).toBe(0);
expect(zoom.mock.calls.length).toBe(0);
DOM.fireEvent(nextElem, 'click');
expect(next.mock.calls.length).toBe(1);
DOM.fireEvent(prevElem, 'click');
expect(prev.mock.calls.length).toBe(1);
DOM.fireEvent(counter, 'click');
expect(zoom.mock.calls.length).toBe(1);
});

View File

@@ -0,0 +1,67 @@
import Scroll from '../../src/js/plugins/scroll';
jest.useFakeTimers();
// Copy of DOM.fireEvent, but using wheel deltas
const fireEvent = (target, eventType, deltaX, deltaY) => {
const event = new CustomEvent(eventType);
event.deltaX = deltaX;
event.deltaY = deltaY;
event.deltaMode = 0;
target.dispatchEvent(event);
};
beforeAll(() => {
const brs = '<br />'.repeat(20);
document.body.innerHTML = `<div id="webslides">${brs}</div>`;
});
test('Scroll utility', () => {
// Forces mobile detection
window.navigator = {
userAgent: 'Android'
};
const ws = document.getElementById('webslides');
const next = jest.fn();
const prev = jest.fn();
let disabled = true;
const webslides = {
el: ws,
isDisabled: () => disabled,
isMoving: false,
isVertical: false,
goNext: next,
goPrev: prev,
options: {
navigateOnScroll: true,
scrollWait: 200,
minWheelDelta: 50
}
};
new Scroll(webslides);
fireEvent(ws, 'wheel', 300, 200);
expect(next).not.toBeCalled();
expect(prev).not.toBeCalled();
// Wait until next execution
jest.runTimersToTime(201);
expect(next.mock.calls.length).toBe(0);
expect(prev.mock.calls.length).toBe(0);
disabled = false;
fireEvent(ws, 'wheel', 300, 200);
jest.runTimersToTime(201);
expect(next.mock.calls.length).toBe(1);
expect(prev.mock.calls.length).toBe(0);
fireEvent(ws, 'wheel', -200, -300);
jest.runTimersToTime(201);
expect(next.mock.calls.length).toBe(1);
expect(prev.mock.calls.length).toBe(1);
});

View File

@@ -0,0 +1,80 @@
import Touch from '../../src/js/plugins/touch';
// Copy of DOM.fireEvent, but using touch offets
const getEvent = (eventType, offsetX, offsetY, touches) => {
const event = new CustomEvent(eventType);
event.offsetX = offsetX;
event.offsetY = offsetY;
event.touches = touches;
return event;
};
beforeAll(() => {
const brs = '<br />'.repeat(20);
document.body.innerHTML = `<div id="webslides">${brs}</div>`;
});
test('Touch utility', () => {
// Overrides userAgent to force mobile detection
Object.getOwnPropertyDescriptor(window.navigator.__proto__, 'userAgent');
Object.defineProperty(window.navigator, 'userAgent', {get: () => 'Android'});
const ws = document.getElementById('webslides');
const next = jest.fn();
const prev = jest.fn();
const zoom = jest.fn();
let disabled = true;
const webslides = {
el: ws,
isDisabled: () => disabled,
isMoving: false,
isVertical: false,
goNext: next,
goPrev: prev,
toggleZoom: zoom,
options: {
slideOffset: 100
}
};
const touch = new Touch(webslides);
touch.onStart_(getEvent('touchstart', 200, 200, [1]));
touch.onMove_(getEvent('touchstart', 200, 400, [1]));
touch.onStop_(getEvent('touchstart', 200, 200, [1]));
expect(next).not.toBeCalled();
expect(prev).not.toBeCalled();
expect(zoom).not.toBeCalled();
disabled = false;
touch.onStart_(getEvent('touchstart', 800, 200, [1]));
touch.onMove_(getEvent('touchstart', 400, 400, [1]));
touch.onStop_(getEvent('touchstart', 400, 200, [1]));
expect(next.mock.calls.length).toBe(1);
expect(prev.mock.calls.length).toBe(0);
expect(zoom.mock.calls.length).toBe(0);
touch.onStart_(getEvent('touchstart', 200, 200, [1]));
touch.onMove_(getEvent('touchstart', 400, 200, [1]));
touch.onStop_(getEvent('touchstart', 400, 200, [1]));
expect(next.mock.calls.length).toBe(1);
expect(prev.mock.calls.length).toBe(1);
expect(zoom.mock.calls.length).toBe(0);
touch.onStart_(getEvent('touchstart', 200, 200,
[{clientX: 100, clientY: 100}, {clientX: 400, clientY: 400}]));
touch.onMove_(getEvent('touchstart', 400, 200,
[{clientX: 200, clientY: 200}, {clientX: 300, clientY: 300}]));
touch.onStop_(getEvent('touchstart', 400, 200,
[{clientX: 200, clientY: 200}, {clientX: 300, clientY: 300}]));
expect(next.mock.calls.length).toBe(1);
expect(prev.mock.calls.length).toBe(1);
expect(zoom.mock.calls.length).toBe(1);
});

View File

@@ -0,0 +1,40 @@
import Video from '../../src/js/plugins/video';
import DOM from '../../src/js/utils/dom';
beforeAll(() => {
const slides = '12345'.replace(/(\d)/g,
'<div id="section-$1" class="slide"><video autoplay="true" /></div>');
document.body.innerHTML = `<div id="webslides">${slides}</div>`;
});
test('Video utility', () => {
const ws = document.getElementById('webslides');
const slides = ws.querySelectorAll('.slide');
const videos = ws.querySelectorAll('video');
const play = jest.fn();
const pause = jest.fn();
videos.forEach(video => {
video.play = play;
video.pause = pause;
});
const webslides = {
el: ws,
slides: []
};
slides.forEach(slide => webslides.slides.push({el: slide}));
expect(ws.querySelectorAll('video[autoplay]').length).toBe(5);
new Video(webslides);
expect(ws.querySelectorAll('video[autoplay]').length).toBe(0);
expect(pause.mock.calls.length).toBe(5);
webslides.slides.forEach(slide => {
DOM.fireEvent(slide.el, 'slide:enable', {slide: slide});
DOM.fireEvent(slide.el, 'slide:disable', {slide: slide});
});
expect(pause.mock.calls.length).toBe(10);
});

View File

@@ -0,0 +1,89 @@
import YouTube from '../../src/js/plugins/youtube';
import DOM from '../../src/js/utils/dom';
beforeAll(() => {
const video = '<div id="section-1" class="slide"><div class="embed">' +
'<div data-youtube="video" ' +
' data-youtube-id="CQY3KUR3VzM" ' +
' data-autoplay data-loop></div></div></div>';
document.body.innerHTML =
`<script></script><div id="webslides">${video}</div>`;
});
test('YouTube utility', () => {
const ws = document.getElementById('webslides');
const slides = ws.querySelectorAll('.slide');
const play = jest.fn();
const pause = jest.fn();
const destroy = jest.fn();
const create = jest.fn();
const webslides = {
el: ws,
slides: []
};
slides.forEach(slide => webslides.slides.push({el: slide}));
window.YT = {
Player: function(a, b) {
return {
getIframe: () => {
const div = DOM.createNode('div');
div.innerHTML =
`<iframe id="widget8"
src="https://www.youtube.com/embed/_m67JbGjWnc"
data-youtube-id="_m67JbGjWnc"
frameborder="0" height="360" width="640"></iframe>`;
webslides.slides[0].el.appendChild(div);
return div.querySelector('iframe');
}
};
}
};
new YouTube(webslides);
expect(typeof window.onYouTubeIframeAPIReady).toBe('function');
const el = webslides.el.querySelector('[data-youtube]');
el.dataset.autoplay = true;
el.dataset.youtubeId = 'CQY3KUR3VzM';
window.onYouTubeIframeAPIReady();
const slide = {
slide: {
player: {
autoplay: true,
play: play,
pause: pause,
destroy: destroy,
create: create
}
}
};
DOM.fireEvent(webslides.slides[0].el, 'dom:enter', slide);
expect(play.mock.calls.length).toBe(0);
expect(pause.mock.calls.length).toBe(0);
expect(destroy.mock.calls.length).toBe(0);
expect(create.mock.calls.length).toBe(1);
DOM.fireEvent(webslides.slides[0].el, 'dom:leave', slide);
expect(play.mock.calls.length).toBe(0);
expect(pause.mock.calls.length).toBe(0);
expect(destroy.mock.calls.length).toBe(1);
expect(create.mock.calls.length).toBe(1);
DOM.fireEvent(webslides.slides[0].el, 'slide:enable', slide);
expect(play.mock.calls.length).toBe(1);
expect(pause.mock.calls.length).toBe(0);
expect(destroy.mock.calls.length).toBe(1);
expect(create.mock.calls.length).toBe(1);
DOM.fireEvent(webslides.slides[0].el, 'slide:disable', slide);
expect(play.mock.calls.length).toBe(1);
expect(pause.mock.calls.length).toBe(1);
expect(destroy.mock.calls.length).toBe(1);
expect(create.mock.calls.length).toBe(1);
});

70
test/plugins/zoom.test.js Normal file
View File

@@ -0,0 +1,70 @@
import Zoom from '../../src/js/plugins/zoom';
import DOM from '../../src/js/utils/dom';
jest.useFakeTimers();
// Copy of DOM.fireEvent, but using keydown
const simulateKeyEvent = (el, code) => {
const evt = new KeyboardEvent('keydown', {
bubbles: true,
cancelableCode: true,
which: code,
shiftKey: true});
el.dispatchEvent(evt);
};
beforeAll(() => {
const slides = '12345'.replace(/(\d)/g,
'<div id="section-$1" class="slide"><div>Slide $1</div></div>')
.replace('section-1" class="', 'section-1" class="current ');
document.body.innerHTML = `<div id="webslides">${slides}</div>`;
});
test('Zoom utility', () => {
const ws = document.getElementById('webslides');
const slides = ws.querySelectorAll('.slide');
const goto = jest.fn();
const enable = jest.fn();
const disable = jest.fn();
const webslides = {
el: ws,
slides: [],
goToSlide: goto,
enable: enable,
disable: disable,
options: {showIndex: true}
};
slides.forEach(slide => webslides.slides.push({el: slide}));
webslides.currentSlide_ = webslides.slides[0];
new Zoom(webslides);
const zws = document.querySelector('#webslides-zoomed');
const zoomSlides = zws.querySelectorAll('.slide');
expect(zws).not.toBe(null);
expect(zws.className).toMatch('disable');
expect(slides.length).toBe(zoomSlides.length);
expect(zws.childNodes[0].className).toBe('wrap');
expect(zws.childNodes[0].childNodes[0].className).toBe('grid');
simulateKeyEvent(document.body, 109);
expect(zws.className).not.toMatch('disable');
// Wait until next execution
jest.runTimersToTime(600);
expect(disable.mock.calls.length).toBe(1);
expect(enable.mock.calls.length).toBe(0);
expect(goto.mock.calls.length).toBe(0);
DOM.fireEvent(zws.querySelector('.zoom-layer'), 'click');
// Wait until next execution
jest.runTimersToTime(401);
expect(disable.mock.calls.length).toBe(1);
expect(enable.mock.calls.length).toBe(1);
expect(goto.mock.calls.length).toBe(1);
});

320
test/utils/dom.test.js Normal file
View File

@@ -0,0 +1,320 @@
import DOM from '../../src/js/utils/dom';
import simulant from 'simulant';
describe('Node creation', () => {
test('Creates a node', () => {
const node = DOM.createNode('p');
expect(node).toBeInstanceOf(Element);
expect(node.tagName).toBe('P');
expect(node.id).toBe('');
});
test('Should be possible to pass an id', () => {
const node = DOM.createNode('p', 'myId');
expect(node.id).toBe('myId');
});
test('Should be possible to pass text', () => {
const node = DOM.createNode('p', 'id', 'foo');
expect(node.textContent).toBe('foo');
});
});
describe('Once', () => {
let parent;
let inner;
beforeEach(() => {
document.body.innerHTML = `
<div id="parent">
<div id="inner"></div>
</div>
`;
parent = document.getElementById('parent');
inner = document.getElementById('inner');
});
afterEach(() => {
document.body.innerHTML = '';
});
test('Only once called once', () => {
const cb = jest.fn();
DOM.once(parent, 'click', cb);
simulant.fire(parent, 'click');
simulant.fire(parent, 'click');
simulant.fire(parent, 'click');
expect(cb).toHaveBeenCalledTimes(1);
});
test('Callback doesn\'t run on bubbled event', () => {
const cb = jest.fn();
DOM.once(parent, 'click', cb);
simulant.fire(inner, 'click');
expect(cb).not.toHaveBeenCalled();
});
});
describe('Transition', () => {
test('Returns unprefixed first if available', () => {
const fakeEl = {
style: {
transition: 'foo',
OTransition: 'foo',
MozTransition: 'foo',
WebkitTransition: 'foo'
}
};
expect(DOM.getTransitionEvent(fakeEl)).toBe('transitionend');
});
test('Prefixed Opera', () => {
const fakeEl = {
style: {
OTransition: 'foo'
}
};
expect(DOM.getTransitionEvent(fakeEl)).toBe('oTransitionEnd');
});
test('Prefixed Gecko', () => {
const fakeEl = {
style: {
MozTransition: 'foo'
}
};
expect(DOM.getTransitionEvent(fakeEl)).toBe('transitionend');
});
test('Prefixed Webkit', () => {
const fakeEl = {
style: {
WebkitTransition: 'foo'
}
};
expect(DOM.getTransitionEvent(fakeEl)).toBe('webkitTransitionEnd');
});
test('Retains value', () => {
const fakeEl = {
style: {
WebkitTransition: 'foo'
}
};
expect(DOM.getTransitionEvent(fakeEl)).toBe('webkitTransitionEnd');
expect(DOM.getTransitionEvent()).toBe('webkitTransitionEnd');
});
});
describe('Animation', () => {
test('Returns unprefixed first if available', () => {
const fakeEl = {
style: {
animation: 'foo',
OAnimation: 'foo',
MozAnimation: 'foo',
WebkitAnimation: 'foo'
}
};
expect(DOM.getAnimationEvent(fakeEl)).toBe('animationend');
});
test('Prefixed Opera', () => {
const fakeEl = {
style: {
OAnimation: 'foo'
}
};
expect(DOM.getAnimationEvent(fakeEl)).toBe('oAnimationEnd');
});
test('Prefixed Gecko', () => {
const fakeEl = {
style: {
MozAnimation: 'foo'
}
};
expect(DOM.getAnimationEvent(fakeEl)).toBe('animationend');
});
test('Prefixed Webkit', () => {
const fakeEl = {
style: {
WebkitAnimation: 'foo'
}
};
expect(DOM.getAnimationEvent(fakeEl)).toBe('webkitAnimationEnd');
});
test('Retains value', () => {
const fakeEl = {
style: {
WebkitAnimation: 'foo'
}
};
expect(DOM.getAnimationEvent(fakeEl)).toBe('webkitAnimationEnd');
expect(DOM.getAnimationEvent()).toBe('webkitAnimationEnd');
});
});
describe('Show/hide', () => {
test('Show removes the display property', () => {
const el = DOM.createNode('div');
el.style.display = 'flex';
expect(el.style.display).toBe('flex');
DOM.show(el);
expect(el.style.display).toBe('');
});
test('Hide adds display none', () => {
const el = DOM.createNode('div');
expect(el.style.display).toBe('');
DOM.hide(el);
expect(el.style.display).toBe('none');
});
test('Is visible', () => {
// offsetParent doesn't work nice with JSDom
const el = DOM.createNode('div');
let offsetParent = document.body;
el.style.display = 'block';
document.body.appendChild(el);
Object.defineProperty(el, 'offsetParent', {get: () => offsetParent});
expect(DOM.isVisible(el)).toBe(true);
DOM.hide(el);
offsetParent = null;
expect(DOM.isVisible(el)).toBe(false);
document.body.removeChild(el);
});
});
describe('Custom Event', () => {
test('Event gets fired', () => {
const cb = jest.fn();
const el = DOM.createNode('div');
el.addEventListener('foo', cb);
DOM.fireEvent(el, 'foo');
expect(cb).toHaveBeenCalled();
});
test('Event can pass data', () => {
const cb = jest.fn();
const el = DOM.createNode('div');
el.addEventListener('foo', cb);
DOM.fireEvent(el, 'foo', {
foo: 'bar'
});
expect(cb.mock.calls[0][0].detail.foo).toBe('bar');
});
});
describe('To Array', () => {
test('Converts to array', () => {
document.body.innerHTML = '<p></p><p></p><p></p><p></p><p></p>';
const paragraphs = document.querySelectorAll('p');
expect(paragraphs.length).toBe(5);
expect(paragraphs).not.toBeInstanceOf(Array);
expect(DOM.toArray(paragraphs)).toBeInstanceOf(Array);
expect(DOM.toArray(paragraphs).length).toBe(5);
document.body.innerHTML = '';
});
});
describe('Focusable Element', () => {
beforeEach(() => {
document.body.innerHTML = `
<p id="noContent" tabindex="0"></p>
<input id="input" type="text">
<select id="select">
<option id="option1"></option>
<option id="option2"></option>
</select>
<textarea id="textarea"></textarea>
`;
});
afterEach(() => {
document.body.innerHTML = '';
});
test('Returns false if not focusable', () => {
document.getElementById('noContent').focus();
expect(DOM.isFocusableElement()).toBe(false);
});
test('Returns true if focusable', () => {
document.getElementById('noContent').focus();
expect(DOM.isFocusableElement()).toBe(false);
document.getElementById('input').focus();
expect(DOM.isFocusableElement()).toBe(true);
document.getElementById('noContent').focus();
expect(DOM.isFocusableElement()).toBe(false);
document.getElementById('select').focus();
expect(DOM.isFocusableElement()).toBe(true);
document.getElementById('noContent').focus();
expect(DOM.isFocusableElement()).toBe(false);
document.getElementById('textarea').focus();
expect(DOM.isFocusableElement()).toBe(true);
});
});
describe('Parse size', () => {
test('Parses a css string to number', () => {
expect(DOM.parseSize('10px')).toBe(10);
});
});
describe('After', () => {
afterEach(() => {
document.body.innerHTML = '';
});
beforeEach(() => {
document.body.innerHTML = '<div id="content">' +
'<div id="1"></div>' +
'<div id="2"></div>' +
'<div id="3"></div>' +
'</div>';
});
test('Inserts node after target', () => {
const content = document.getElementById('content');
const lastDiv = document.getElementById('3');
const secondDiv = document.getElementById('2');
DOM.after(secondDiv, lastDiv);
expect(content.innerHTML)
.toBe('<div id="1"></div><div id="3"></div><div id="2"></div>');
DOM.after(secondDiv, lastDiv);
expect(content.innerHTML)
.toBe('<div id="1"></div><div id="3"></div><div id="2"></div>');
});
});

63
test/utils/hash.test.js Normal file
View File

@@ -0,0 +1,63 @@
import DOM from '../../src/js/utils/dom';
import Hash from '../../src/js/plugins/hash';
describe('Hash utility', () => {
document.body.innerHTML =
`<div id="webslides" data-test="test"><p>Text</p></div>`;
document.location.hash = '#slide=1';
const goto = jest.fn();
const ws = document.getElementById('webslides');
const webslides = {
options: {
changeOnClick: true
},
goToSlide: goto,
el: ws
};
test('Make sure it has not changed the slide', () => {
expect(goto).not.toBeCalled();
});
new Hash(webslides);
test('Move to slide 1', () => {
expect(Hash.getSlideNumber()).toBe(0);
DOM.fireEvent(ws, 'ws:slide-change', {
slides: 3,
currentSlide0: 1,
currentSlide: 2
});
expect(Hash.getSlideNumber()).toBe(1);
expect(document.location.hash).toBe('#slide=2');
DOM.fireEvent(window, 'hashchange');
expect(goto.mock.calls.length).toBe(1);
});
test('Forces slide change', () => {
Hash.setSlideNumber(5);
const state = history.state;
expect(state.slideI).toBe(4);
});
test('Wrong hash', () => {
document.location.hash = 'slide=NaN';
DOM.fireEvent(window, 'hashchange');
// It shouldn't be call.
expect(goto.mock.calls.length).toBe(1);
expect(Hash.getSlideNumber()).toBe(null);
});
test('Repeat slide change', () => {
Hash.setSlideNumber(5);
let state = history.state;
expect(state.slideI).toBe(4);
Hash.setSlideNumber(5);
state = history.state;
expect(state.slideI).toBe(4);
});
});

14
test/utils/keys.test.js Normal file
View File

@@ -0,0 +1,14 @@
import Keys from '../../src/js/utils/keys';
test('Keys are present', () => {
expect(Keys.ENTER).toBe(13);
expect(Keys.SPACE).toBe(32);
expect(Keys.RE_PAGE).toBe(33);
expect(Keys.AV_PAGE).toBe(34);
expect(Keys.END).toBe(35);
expect(Keys.HOME).toBe(36);
expect(Keys.LEFT).toBe(37);
expect(Keys.UP).toBe(38);
expect(Keys.RIGHT).toBe(39);
expect(Keys.DOWN).toBe(40);
});

Some files were not shown because too many files have changed in this diff Show More