Tips (beta)
Slack inspired onboarding tips.
Note: Tips is currently in Beta. Left, much work there is. To see a backlog of features and work currently in progress checkout the HuBoard.
Installation
Add this line to your application's Gemfile:
gem 'tips'
And then execute:
$ bundle
Or install it yourself as:
$ gem install tips
Examples
- Single Tip
- Single Tip, multiple pages of content
- Multiple Tips
- Multiple Tips, multiple pages of content
Usage
Tips uses HTML data-attributes to pass the majority of its configuration.
Creating a tip
Creating a tip is easy. Just add the necessary data-attributes to your target
element and call Tips.init()
. For example, if you want to target a div on your
page you'd add the following data-attributes to the div:
<div data-tips-id='my-unique-tip-name'
data-tips-content='{"page1Header" : "This is my header",
"page1Body" : "This is the body of my tip",
}'
data-tips-hot-spot-position='top-right'
data-tips-card-position='right'
data-tips-priority='1'
data-tips-pages='1'>
</div>
Once the data attributes have been added add this line to your javascript
Tips.init()
Creating multiple tips on a single page
Use the same data-attributes as a single tip just make sure data-tips-id
is
unique for each tip and set the data-tips-priority
appropriately.
<div data-tips-id='my-unique-tip-name'
data-tips-content='{"page1Header" : "This is my header",
"page1Body" : "This is the body of my tip",
}'
data-tips-hot-spot-position='top-right'
data-tips-card-position='right'
data-tips-priority='1'
data-tips-pages='1'>
<button>My 1st Button</button>
</div>
<div data-tips-id='my-unique-tip-name-number-two'
data-tips-content='{"page1Header" : "This is my header no. 2",
"page1Body" : "This is the body of my tip no. 2",
}'
data-tips-hot-spot-position='top-right'
data-tips-card-position='right'
data-tips-priority='2'
data-tips-pages='1'>
<button>My 2nd Button</button>
</div>
Once the data attributes have been added add this line to your javascript
Tips.init()
Creating tips with multiple pages of content
To do this just add the extra pages to data-tips-content
<div data-tips-id='my-unique-tip-name'
data-tips-content='{"page1Header" : "This is my header",
"page1Body" : "This is the body of my tip",
"page2Header" : "A second header?",
"page2Body" : "Yes! If you so choose, you can have
tips with multiple pages."
}'
data-tips-hot-spot-position='top-right'
data-tips-card-position='right'
data-tips-priority='1'
data-tips-pages='1'>
<button>My 1st Button</button>
</div>
Once the data attributes have been added add this line to your javascript
Tips.init()
Attributes overview
data-tips-id
data-tips-id
should be unique for each tip you have on your website.
These are used as references when we check if a user has previously seen a tip.
data-tips-id='some-unique-name-for-this-tip'
data-tips-content
data-tips-content
is a JSON string representation of the content for your tip.
To allow Tips to support multiple pages of content we use keys in the form of
page1Header
and page1Body
. Pages should be sequential. Shit will fail
otherwise.
data-tips-content='{"page1Header":"The header for the first page of this tip",
"page1Boy":"The body for the first page of this tip",
"page2Header":"The header for the second page of this tip",
"page2Body":"The body for the second page of this tip"
}
data-tips-hot-spot-position
data-tips-hot-spot-position
controls the position of the throbbing hot spot
icon in relation to the element you're targeting.
<!-- Default value: 'right' -->
data-tips-hot-spot-position='bottom-left'
Acceptable values:
top-right
top-left
top
bottom-right
bottom-left
bottom
left
right
middle
data-tips-card-position
data-tips-card-position
controls the side your tip modal will show up on.
<!-- Default value: 'right' -->
data-tips-card-position='left'
Acceptable values:
top
bottom
left
right
data-tips-priority
data-tips-priority
is used when you have multiple tips on a given page.
Priority 1 will be shown first.
data-tips-priority='1'
data-tips-pages
data-tips-pages
tells Tips how many pages you want on a given tip. Required
attribute. There is no default set at this point.
data-tips-priority='1'
Storage
Default Storage (localStorage)
By default Tips will use localStorage
to store which tips have been seen.
This works, however, it's sub-optimal. Using localStorage
means tips may be
seen twice. When using localStorage the following scenarios may show tips twice:
- User opens pages in incognito mode
- User opens pages in multiple browsers
- User opens pages from multiple devices
Because the lack of persistence with localStorage
, Tips comes with the ability
to define your own customStorageDevice
.
Here's the defaultStorageDevice
:
var defaultStorageDevice = {
optOutKey: 'tips-opted-out',
addTip: function(tipName){
localStorage.setItem(tipName, true);
},
tipHasBeenSeen: function(tipName){
return !!localStorage.getItem(tipName);
},
optOut: function(){
localStorage.setItem(this.optOutKey, true);
},
userHasOptedOut: function(){
return !!localStorage.getItem(this.optOutKey);
},
removeAll: function(tipNames){
tipNames.push(this.optOutKey);
tipNames.forEach(function(key){
localStorage.removeItem(key);
});
}
};
Custom Storage Device
You can define your own custom storage device and pass it in as an argument when
you initialize with Tips.init(myCustomStorageDevice)
. Example using jQuery
:
(function initTipsWithCustomStorage() {
// Make an ajax call for a list of seen tips and if the user has opted out
// On success, init tips with out customStorageDevice
(function(){
$.ajax('/tips/data', {
method: 'GET'
})
.success(function(data){
var userHasOptedOut = data.optedOut;
var seenTips = data.seenTips;
var storageDevice = {
seenTips: seenTips,
addTip: function(tipName){
$.ajax('/tips/tip_seen', {
method: 'POST',
data: {name: tipName}
});
// Add tip to list of seenTips so it doesn't show again in the same
// window session
seenTips.push(tipName);
},
tipHasBeenSeen: function(tipName){
return seenTips.indexOf(tipName) != -1;
},
optOut: function(){
$.ajax('/tips/opted_out', {
method: 'POST',
data: {name: 'opt-out'}
})
},
userHasOptedOut: function(){
return !!userHasOptedOut;
},
};
// Begin the magic
Tips.init(storageDevice);
})
.fail(function(jqXHR, textStatus){
console.log('Failure? Yes, failure with status: ' + textStatus)
});
})();
})();
Important things to note here
- You're passing an object with public methods, not a function
- You must have the following methods defined
javascript storageDevice.addTip() storageDevice.tipHasBeenSeen() storageDevice.optOut() storageDevice.userHasOptedOut()
Contributing
- Fork it ( http://github.com/
/tips/fork ) - Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request