Skip to content

Commit

Permalink
Scroll animation with category highlight
Browse files Browse the repository at this point in the history
  • Loading branch information
unimonkiez committed Apr 25, 2016
1 parent faa018b commit c351d7a
Show file tree
Hide file tree
Showing 47 changed files with 131 additions and 60,313 deletions.
Binary file removed dist/asset/2198fb90cd396e781a7aabb224c248e4.png
Binary file not shown.
Binary file removed dist/asset/2a7cd0e77c69514a9374e78dc58766e9.png
Binary file not shown.
Binary file removed dist/asset/37719639e33dc78bbdb894613d157a5b.png
Binary file not shown.
Binary file removed dist/asset/4bd751016ed11aae11c1484a3a883996.png
Binary file not shown.
Binary file removed dist/asset/582ccf2590bc64e38113cc76ba71af4f.png
Binary file not shown.
Binary file removed dist/asset/8c441eb1bf425dab65ca0f20127bfbe5.png
Binary file not shown.
Binary file removed dist/asset/8ed75e4accbc7b61f1a53e0b871d8dee.png
Binary file not shown.
Binary file removed dist/asset/968517b0ef1f7e790b0df13e67c42908.png
Binary file not shown.
Binary file removed dist/asset/9c7faf66d0f9866420f97fcca52c4444.png
Binary file not shown.
Binary file removed dist/asset/c51702ccb711180c483011345e7efc8a.png
Binary file not shown.
Binary file removed dist/asset/c6a99e0b8d1aa7c403d7f4b70afc69f7.png
Binary file not shown.
Binary file removed dist/asset/c89a7cdb9874a8f485ab3eb1deb0187d.png
Binary file not shown.
Binary file removed dist/asset/c99d7c94cff6634c6d949d18c39331c7.png
Binary file not shown.
Binary file removed dist/asset/cc9d6b0e6925706d26a4df2b23ebecb2.png
Binary file not shown.
Binary file removed dist/asset/dd31a73e9973d39cee5d9de2616ad911.png
Binary file not shown.
Binary file removed dist/asset/fbf4560dfce272c3e6523c638c58f9f9.png
Binary file not shown.
3,730 changes: 0 additions & 3,730 deletions dist/emoji-panel-apple-16.css

This file was deleted.

3,730 changes: 0 additions & 3,730 deletions dist/emoji-panel-apple-20.css

This file was deleted.

3,730 changes: 0 additions & 3,730 deletions dist/emoji-panel-apple-32.css

This file was deleted.

3,730 changes: 0 additions & 3,730 deletions dist/emoji-panel-apple-64.css

This file was deleted.

3,733 changes: 0 additions & 3,733 deletions dist/emoji-panel-emojione-16.css

This file was deleted.

3,733 changes: 0 additions & 3,733 deletions dist/emoji-panel-emojione-20.css

This file was deleted.

3,733 changes: 0 additions & 3,733 deletions dist/emoji-panel-emojione-32.css

This file was deleted.

3,733 changes: 0 additions & 3,733 deletions dist/emoji-panel-emojione-64.css

This file was deleted.

3,733 changes: 0 additions & 3,733 deletions dist/emoji-panel-google-16.css

This file was deleted.

3,733 changes: 0 additions & 3,733 deletions dist/emoji-panel-google-20.css

This file was deleted.

3,733 changes: 0 additions & 3,733 deletions dist/emoji-panel-google-32.css

This file was deleted.

3,733 changes: 0 additions & 3,733 deletions dist/emoji-panel-google-64.css

This file was deleted.

3,733 changes: 0 additions & 3,733 deletions dist/emoji-panel-twitter-16.css

This file was deleted.

3,733 changes: 0 additions & 3,733 deletions dist/emoji-panel-twitter-20.css

This file was deleted.

3,733 changes: 0 additions & 3,733 deletions dist/emoji-panel-twitter-32.css

This file was deleted.

3,733 changes: 0 additions & 3,733 deletions dist/emoji-panel-twitter-64.css

This file was deleted.

264 changes: 0 additions & 264 deletions dist/emoji-panel.js

This file was deleted.

3 changes: 0 additions & 3 deletions dist/example.css

This file was deleted.

294 changes: 0 additions & 294 deletions dist/example.js

This file was deleted.

4 changes: 3 additions & 1 deletion example/example.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import EmojiPanel from 'emoji-panel';

new EmojiPanel(document.getElementById('panel-example-1'));
new EmojiPanel(document.getElementById('panel-example-1'), { onClick: ({ index } = {}) => {
console.log(index);
} });
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
</div>
<script type="text/javascript" src="dist/example.min.js"></script>
<link rel="stylesheet" href="dist/example.min.css">
<link rel="stylesheet" href="dist/emoji-panel-apple-32.css">
<link rel="stylesheet" href="dist/emoji-panel-apple-32.min.css">
</body>
</html>
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --progress && rimraf ./dist/emoji-panel-*.js",
"start": "webpack-dev-server --port 8080 --inline --progress --colors --config ./webpack.dev.config.js",
"start:prod": "set NODE_ENV=production&& npm start",
"predeploy": "set NODE_ENV=development&& npm run build && set NODE_ENV=production&& npm run build",
"deploy": "npm run predeploy && git add dist && git add dist/* && git commit -m \"Deploy build files\" && git checkout gh-pages && git merge master && git push && git checkout master && git push"
},
Expand Down Expand Up @@ -37,6 +38,7 @@
"eslint": "^2.7.0",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5",
"html-minify-loader": "^1.1.0",
"html-webpack-plugin": "^2.15.0",
"json-loader": "^0.5.4",
"node-sass": "^3.4.2",
Expand Down
1 change: 1 addition & 0 deletions src/category-order.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const CATEGORY = require('./constant').CATEGORY;
module.exports = [
CATEGORY.PEOPLE,
CATEGORY.NATURE,
CATEGORY.FOODS,
CATEGORY.ACTIVITY,
CATEGORY.PLACES,
CATEGORY.OBJECTS,
Expand Down
4 changes: 2 additions & 2 deletions src/create-panel.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import panelTemplate from './template.ahtml';
import setEventsForTemplate from './set-events-for-template';

export default ({ imageSet, size, animationDuration } = {}) => {
export default ({ animationDuration, panelVariables, eventListeners } = {}) => {
const panelEl = document.createElement('div');
panelEl.setAttribute('class', 'ep-container');
panelEl.innerHTML = panelTemplate;
setEventsForTemplate(panelEl, { animationDuration });
setEventsForTemplate(panelEl, { animationDuration, panelVariables, eventListeners });

return panelEl;
};
28 changes: 16 additions & 12 deletions src/emoji-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,29 @@ import { IMAGE_SET, SIZE } from './constant';
import createPanel from './create-panel';

export default class EmojiPanel {
constructor(el, { imageSet = IMAGE_SET.APPLE, size = SIZE['64'], animationDuration = 300 } = {}) {
constructor(el, { animationDuration = 300, onClick } = {}) {
if (__DEV__) {
if (!(el && el.nodeType)) {
throw new Error('Element must be provided to the first argument of `EmojiPanel` constructor.');
}
if (Object.keys(IMAGE_SET).map(key => IMAGE_SET[key]).indexOf(imageSet) === -1) {
throw new Error('`imageSet` should have one of `EmojiPanel.IMAGE_SET` values, got ${imageSet}.');
if (typeof animationDuration !== 'number') {
throw new Error('`animationDuration` should be a number, got ${typeof animationDuration}.');
}
if (onClick !== undefined && typeof onClick !== 'function') {
throw new Error('`onClick` should be a function, got ${typeof onClick}.');
}
}
const windowImageSet = createPanel({ imageSet, size, animationDuration });
// Privates
this._panelVariables = {};
this._eventListeners = { onClick };

const windowImageSet = createPanel({
animationDuration,
panelVariables: this._panelVariables,
eventListeners: this._eventListeners
});

el.innerHTML = '';
el.appendChild(windowImageSet);

// Privates
this._eventListeners = {
click: []
};
}
}
// EmojiPanel static properties
EmojiPanel.IMAGE_SET = IMAGE_SET;
EmojiPanel.SIZE = SIZE;
27 changes: 27 additions & 0 deletions src/emoji-panel.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,43 @@

$size-categories-icons: 32px;
$size-categories: 40px;
$size-slide: 3px;

.ep {
height: 100%;

user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;

::-webkit-scrollbar {
width: 6px!important;
}
::-webkit-scrollbar-thumb {
background-color: rgba(0,0,0,.2);
}
::-webkit-scrollbar-track {
background: rgba(255,255,255,.08);
}
}
.ep-container {
height: 100%;
}
.ep-categories {
height: $size-categories;
padding-bottom: $size-slide;
display: flex;
position: relative;
}
.ep-slide {
position: absolute;
height: $size-slide;
width: 12.5%;
will-change: margin-left;
transition: margin-left ease-in-out;
background-color: #93D3CC;
bottom: 0;
}
.ep-c {
cursor: pointer;
Expand Down
5 changes: 3 additions & 2 deletions src/emoji.data.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ const emojiData = require('emoji-data');
const categoryDataMap = require('./map').categoryDataMap;

const sortedEmojiData = emojiData
.map((emoji, index) => Object.assign(emoji, { index }))
.sort((emojiA, emojiB) => emojiA['sort_order'] - emojiB['sort_order'])
.reduce((obj, emoji, index) => {
.reduce((obj, emoji) => {
const category = categoryDataMap[emoji.category];
const categoryArray = obj[category] || [];
return Object.assign(obj, {
[category]: categoryArray.concat(Object.assign(emoji, { index }))
[category]: categoryArray.concat(emoji)
});
}, {});

Expand Down
55 changes: 52 additions & 3 deletions src/set-events-for-template.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// import emojiData from 'emoji-data';
import categoryOrder from './category-order';
import { CATEGORY } from './constant';

const getIsElementScrollable = el => {
return el.clientHeight !== el.scrollHeight;
};
Expand All @@ -18,7 +22,7 @@ const scrollElementTo = (el, done, newScrollHeight = 0, scrollDuration = 300) =>
requestAnimationFrame(step);
scrollCount = scrollCount + 1;
scrollMargin = round(cosParameter - cosParameter * Math.cos(scrollCount * scrollStep));
el.scrollTo(0, scrollHeight - scrollMargin);
el.scrollTop = scrollHeight - scrollMargin;
} else {
done();
}
Expand All @@ -27,11 +31,36 @@ const scrollElementTo = (el, done, newScrollHeight = 0, scrollDuration = 300) =>

requestAnimationFrame(step);
};
export default (el, { animationDuration } = {}) => {

const marginParam = 100 / categoryOrder.length;
const slideToCategory = (panelVariables, slideEl, categoryId) => {
if (panelVariables.selectedCategoryId !== categoryId) {
panelVariables.selectedCategoryId = categoryId;
const selectedCategoryIndex = categoryOrder.indexOf(categoryId);
slideEl.style.marginLeft = selectedCategoryIndex * marginParam + '%';
}
};

export default (el, { animationDuration, panelVariables, eventListeners } = {}) => {
let isMidScrollAnimation = false;

const categoriesEl = el.querySelector('.ep-categories');
const slideEl = el.querySelector('.ep-slide');
const emojiesContainer = el.querySelector('.ep-emojies');

// Set styles
slideEl.style.transitionDuration = animationDuration + 'ms';

const scrollListener = () => {
const scrollHeight = emojiesContainer.scrollTop;
const emojiesContainerChildren = Array.from(emojiesContainer.children);
const lastVisibleContainerChild = emojiesContainerChildren
.find(node => scrollHeight >= node.offsetTop && (!node.nextElementSibling || scrollHeight < node.nextElementSibling.offsetTop));

const categoryId = Number(lastVisibleContainerChild.dataset.categoryId);
slideToCategory(panelVariables, slideEl, categoryId);
};

categoriesEl.addEventListener('click', e => {
if (isMidScrollAnimation === false) {
let target = e.target;
Expand All @@ -41,15 +70,35 @@ export default (el, { animationDuration } = {}) => {
if (target.classList.contains('ep-c')) {
const isElementScrollable = getIsElementScrollable(emojiesContainer);
if (isElementScrollable) {
const categoryId = target.dataset.categoryId;
const categoryId = Number(target.dataset.categoryId);
const categoryEl = emojiesContainer.querySelector(`[data-category-id="${categoryId}"]`);
const categoryHeight = categoryEl.offsetTop;

isMidScrollAnimation = true;
// Remove scroll event listener for better performance
emojiesContainer.removeEventListener('scroll', scrollListener);
scrollElementTo(emojiesContainer, () => {
isMidScrollAnimation = false;
// Readd scroll event listener after javascript animation has finished
emojiesContainer.addEventListener('scroll', scrollListener);
}, categoryHeight, animationDuration);

slideToCategory(panelVariables, slideEl, categoryId);
}
}
}
});

emojiesContainer.addEventListener('scroll', scrollListener);

if (eventListeners.onClick) {
emojiesContainer.addEventListener('click', e => {
const target = e.target;
if (target.classList.contains('ep-e')) {
const index = Number(target.dataset.index);
const unified = target.dataset.unified;
eventListeners.onClick({ index, unified });
}
});
}
};
25 changes: 14 additions & 11 deletions src/template.ahtml.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,21 @@ const categoryNameMap = Map.categoryNameMap;
module.exports = api => {
api.morph('html').add({
'div[class="ep"]': {
'div[class="ep-categories"]': categoryOrder.reduce((obj, category) => Object.assign(obj, {
[`span[class="ep-c" data-category-id="${category}"]`]: {
[`span[class="cat cat-${category}"]`]: '',
'span[class="ep-c-text"]': categoryNameMap[category]
}
}), {}),
'div[class="ep-categories"]': [
{
'span[class="ep-slide"]': ''
},
categoryOrder.reduce((obj, category) => Object.assign(obj, {
[`span[class="ep-c" data-category-id="${category}"]`]: {
[`span[class="cat cat-${category}"]`]: '',
'span[class="ep-c-text"]': categoryNameMap[category]
}
}), {})
],
'div[class="ep-emojies"]': categoryOrder.reduce((catObj, category) => Object.assign(catObj, {
[`div[class="ep-emojies-c" data-category-id="${category}"]`]: {
'div': emojiData[category].reduce((emojiObj, emoji) => Object.assign(emojiObj, {
[`span[class="ep-e" data-index="${emoji.index}"]`]: ''
}), {})
}
[`div[class="ep-emojies-c" data-category-id="${category}"]`]: emojiData[category].reduce((emojiObj, emoji) => Object.assign(emojiObj, {
[`span[class="ep-e" data-index="${emoji.index}" data-unified="${emoji.unified}"]`]: ''
}), {})
}), {})
}
});
Expand Down
2 changes: 1 addition & 1 deletion webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ module.exports = {
include: [
path.resolve(__dirname, 'src')
],
loader: 'raw!absurd'
loader: 'raw!html-minify!absurd'
},
{
test: /\.acss.js$/,
Expand Down
12 changes: 9 additions & 3 deletions webpack.dev.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@ const webpackBaseConfig = require('./webpack.config');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const __PROD__ = process.env.NODE_ENV === 'production';

module.exports =
Object.assign(webpackBaseConfig, {
devtool: 'source-map',
entry: Object.assign({}, {
'dist/example.min': webpackBaseConfig.entry.example, // Change location and file name to match the ones in github page
entry: Object.assign({
base: [] // Hot reload will be injected here
}),
},
Object.keys(webpackBaseConfig.entry)
.filter(entryName => entryName !== 'emoji-panel')
.reduce((obj, entryName) => Object.assign(obj, {
[`dist/${entryName}${__PROD__ ? '' : '.min'}`]: webpackBaseConfig.entry[entryName]
}), {})),
module: Object.assign(webpackBaseConfig.module, {
loaders: webpackBaseConfig.module.loaders.map(loaderObj => {
const loaderTestString = loaderObj.test.toString();
Expand Down

0 comments on commit c351d7a

Please sign in to comment.