mvpkit 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +30 -0
- data/Gemfile.lock +329 -0
- data/LICENSE.txt +20 -0
- data/MIT-LICENSE +20 -0
- data/README.md +134 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/app/assets/javascripts/mvp/application.js +1 -0
- data/app/assets/stylesheets/mvp/application.scss +0 -0
- data/app/controllers/concerns/mvp/analytics_concern.rb +78 -0
- data/app/controllers/concerns/mvp/seo_concern.rb +25 -0
- data/app/controllers/concerns/mvp/session_concern.rb +44 -0
- data/app/controllers/mvp/analytics_controller.rb +12 -0
- data/app/controllers/mvp/seo_controller.rb +11 -0
- data/app/controllers/mvp/styleguide_controller.rb +23 -0
- data/app/helpers/minimum_viable_product/body_helper.rb +14 -0
- data/app/helpers/minimum_viable_product/bootstrap_helper.rb +38 -0
- data/app/helpers/minimum_viable_product/styleguide_helper.rb +4 -0
- data/app/models/concerns/mvp/slugification.rb +24 -0
- data/app/views/layouts/minimum_viable_product/_instrumentation.html.erb +100 -0
- data/app/views/layouts/minimum_viable_product/_meta.html.erb +37 -0
- data/app/views/layouts/minimum_viable_product/application.html.erb +19 -0
- data/app/views/minimum_viable_product/styleguide/_example.html.erb +6 -0
- data/app/views/minimum_viable_product/styleguide/bootstrap/_buttons.html.erb +191 -0
- data/app/views/minimum_viable_product/styleguide/bootstrap/_forms.html.erb +192 -0
- data/app/views/minimum_viable_product/styleguide/bootstrap/_header.html.erb +48 -0
- data/app/views/minimum_viable_product/styleguide/bootstrap/_panels.html.erb +16 -0
- data/app/views/minimum_viable_product/styleguide/bootstrap/_tables.html.erb +34 -0
- data/app/views/minimum_viable_product/styleguide/bootstrap/_typography.html.erb +51 -0
- data/app/views/minimum_viable_product/styleguide/bootstrap.html.erb +43 -0
- data/app/views/minimum_viable_product/styleguide/elements/_grouping.html.erb +1 -0
- data/app/views/minimum_viable_product/styleguide/elements/partials/_row_groups_of.html.erb +7 -0
- data/app/views/minimum_viable_product/styleguide/index.html.erb +17 -0
- data/app/views/minimum_viable_product/styleguide/layouts/basic.html.erb +4 -0
- data/app/views/minimum_viable_product/styleguide/layouts/carousel.html.erb +120 -0
- data/app/views/minimum_viable_product/styleguide/layouts/cover.html.erb +34 -0
- data/assets/js/application.js +31 -0
- data/assets/js/init/controllers.js +26 -0
- data/assets/js/init/forms.js +12 -0
- data/bin/mvp +78 -0
- data/bin/rails +12 -0
- data/config/initializers/assets.rb +2 -0
- data/config/initializers/canonical_host.rb +3 -0
- data/config/initializers/cloudinary.rb +7 -0
- data/config/initializers/geocoder.rb +9 -0
- data/config/initializers/iteration.rb +33 -0
- data/config/initializers/project.rb +1 -0
- data/config/initializers/rollbar.rb +59 -0
- data/config/initializers/routing.rb +7 -0
- data/config/initializers/spoof_ip.rb +33 -0
- data/config/initializers/ssl.rb +14 -0
- data/config/routes.rb +6 -0
- data/lib/mvp/engine.rb +22 -0
- data/lib/mvp/ext/nil.rb +5 -0
- data/lib/mvp/ext/string.rb +7 -0
- data/lib/mvpkit.rb +6 -0
- data/lib/tasks/sitemap.rake +42 -0
- data/mvpkit.gemspec +245 -0
- data/package.json +43 -0
- data/project/.gitignore +45 -0
- data/project/Gemfile +33 -0
- data/project/Gemfile.lock +437 -0
- data/project/Procfile +2 -0
- data/project/README.md +117 -0
- data/project/Rakefile +14 -0
- data/project/app/controllers/application_controller.rb +12 -0
- data/project/app/controllers/conversions_controller.rb +24 -0
- data/project/app/controllers/examples_controller.rb +2 -0
- data/project/app/controllers/home_controller.rb +7 -0
- data/project/app/decorators/.keep +0 -0
- data/project/app/helpers/application_helper.rb +24 -0
- data/project/app/mailers/.keep +0 -0
- data/project/app/models/conversion.rb +4 -0
- data/project/app/views/examples/index.html.erb +1 -0
- data/project/app/views/examples/mustache/template.mustache +1 -0
- data/project/app/views/examples/mustache.html.erb +18 -0
- data/project/app/views/home/conversion.html.erb +12 -0
- data/project/app/views/home/index.html.erb +28 -0
- data/project/app/views/layouts/_header.html.erb +16 -0
- data/project/app/views/layouts/_includes.html.erb +7 -0
- data/project/app/views/layouts/application.html.erb +17 -0
- data/project/app/views/layouts/modal.html.erb +14 -0
- data/project/assets/images/.keep +0 -0
- data/project/assets/images/favicon.ico +0 -0
- data/project/assets/javascripts/controllers/home.coffee +15 -0
- data/project/assets/javascripts/pack.js +9 -0
- data/project/assets/stylesheets/config/variables.scss +876 -0
- data/project/assets/stylesheets/layout/basic.scss +6 -0
- data/project/assets/stylesheets/layout/carousel.scss +127 -0
- data/project/assets/stylesheets/layout/cover.scss +129 -0
- data/project/assets/stylesheets/lib/spacing.scss +55 -0
- data/project/assets/stylesheets/skin/style.scss +16 -0
- data/project/assets/stylesheets/style.scss +8 -0
- data/project/bin/bundle +3 -0
- data/project/bin/rails +9 -0
- data/project/bin/rake +9 -0
- data/project/bin/setup +32 -0
- data/project/bin/spring +15 -0
- data/project/config/application.rb +32 -0
- data/project/config/boot.rb +3 -0
- data/project/config/database.yml +19 -0
- data/project/config/environment.rb +5 -0
- data/project/config/environments/development.rb +67 -0
- data/project/config/environments/production.rb +93 -0
- data/project/config/environments/test.rb +42 -0
- data/project/config/initializers/assets.rb +11 -0
- data/project/config/initializers/backtrace_silencers.rb +7 -0
- data/project/config/initializers/cookies_serializer.rb +3 -0
- data/project/config/initializers/filter_parameter_logging.rb +4 -0
- data/project/config/initializers/inflections.rb +16 -0
- data/project/config/initializers/mime_types.rb +4 -0
- data/project/config/initializers/mustache.rb +7 -0
- data/project/config/initializers/rails_admin.rb +43 -0
- data/project/config/initializers/session_store.rb +3 -0
- data/project/config/initializers/simple_form.rb +177 -0
- data/project/config/initializers/wrap_parameters.rb +14 -0
- data/project/config/locales/en.yml +23 -0
- data/project/config/locales/simple_form.en.yml +31 -0
- data/project/config/routes.rb +13 -0
- data/project/config/secrets.yml +8 -0
- data/project/config/sitemap.rb +28 -0
- data/project/config.ru +4 -0
- data/project/db/migrate/20160728235100_create_conversions.rb +9 -0
- data/project/db/schema.rb +25 -0
- data/project/db/seeds.rb +7 -0
- data/project/lib/assets/.keep +0 -0
- data/project/lib/tasks/heroku.rake +70 -0
- data/project/log/.keep +0 -0
- data/project/log/development.log +48216 -0
- data/project/log/production.log +0 -0
- data/project/package.json +44 -0
- data/project/public/404.html +67 -0
- data/project/public/422.html +67 -0
- data/project/public/500.html +66 -0
- data/project/public/assets/javascripts/448c34a56d699c29117adc64c43affeb.woff2 +0 -0
- data/project/public/assets/javascripts/89889688147bd7575d6327160d64e760.svg +288 -0
- data/project/public/assets/javascripts/e18bbf611f2a2e43afc071aa2f4e1512.ttf +0 -0
- data/project/public/assets/javascripts/f4769f9bdb7466be65088239c12046d1.eot +0 -0
- data/project/public/assets/javascripts/fa2772327f55d8198301fdb8bcfc8158.woff +0 -0
- data/project/public/assets/javascripts/pack.js +31367 -0
- data/project/public/assets/javascripts/pack.js.map +1 -0
- data/project/public/assets/pack.js +17220 -0
- data/project/public/assets/style.css +7477 -0
- data/project/vendor/assets/javascripts/.keep +0 -0
- data/project/vendor/assets/stylesheets/.keep +0 -0
- data/project/webpack.config.js +67 -0
- data/test/helper.rb +34 -0
- data/test/test_minimum_viable_product.rb +7 -0
- metadata +473 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
module MVP
|
2
|
+
module SessionConcern
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
COOKIE_ID = '_session'
|
6
|
+
|
7
|
+
included do
|
8
|
+
helper_method :current_user
|
9
|
+
end
|
10
|
+
|
11
|
+
def current_user=(user)
|
12
|
+
session[COOKIE_ID] = user.id
|
13
|
+
end
|
14
|
+
alias_method :sign_in, :current_user=
|
15
|
+
|
16
|
+
def current_user
|
17
|
+
@current_user ||= begin
|
18
|
+
if session[COOKIE_ID]
|
19
|
+
Conversion.find(session[COOKIE_ID])
|
20
|
+
end
|
21
|
+
rescue ActiveRecord::RecordNotFound
|
22
|
+
session[COOKIE_ID] = nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# http://blog.laaz.org/tech/2012/12/27/rails-redirect_back_or_default/
|
27
|
+
def store_location(path=nil)
|
28
|
+
session[:return_to] = case
|
29
|
+
when !path.nil?
|
30
|
+
path
|
31
|
+
when request.get?
|
32
|
+
request.url
|
33
|
+
else
|
34
|
+
request.referer
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# http://blog.laaz.org/tech/2012/12/27/rails-redirect_back_or_default/
|
39
|
+
def redirect_back_or_default(default=nil)
|
40
|
+
redirect_to(session.delete(:return_to) || default || request.referer)
|
41
|
+
end
|
42
|
+
alias_method :redirect_to_back_or_default, :redirect_back_or_default
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module MinimumViableProduct
|
2
|
+
class StyleguideController < ActionController::Base
|
3
|
+
def index
|
4
|
+
render layout: 'minimum_viable_product/basic'
|
5
|
+
end
|
6
|
+
|
7
|
+
def bootstrap
|
8
|
+
render layout: 'minimum_viable_product/basic'
|
9
|
+
end
|
10
|
+
|
11
|
+
def layout_basic
|
12
|
+
render template: 'minimum_viable_product/styleguide/layouts/basic', layout: 'minimum_viable_product/basic'
|
13
|
+
end
|
14
|
+
|
15
|
+
def layout_cover
|
16
|
+
render template: 'minimum_viable_product/styleguide/layouts/cover', layout: 'minimum_viable_product/cover'
|
17
|
+
end
|
18
|
+
|
19
|
+
def layout_carousel
|
20
|
+
render template: 'minimum_viable_product/styleguide/layouts/carousel', layout: 'minimum_viable_product/carousel'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module MinimumViableProduct
|
2
|
+
module BodyHelper
|
3
|
+
def body_id
|
4
|
+
"#{controller_name}-#{action_name}-page"
|
5
|
+
end
|
6
|
+
|
7
|
+
def body_classes
|
8
|
+
klass = []
|
9
|
+
klass << "#{controller_name}-pages"
|
10
|
+
klass << page.classes if page.classes.present?
|
11
|
+
klass.join(' ')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module MinimumViableProduct
|
2
|
+
module BootstrapHelper
|
3
|
+
def col_groups_of(count, collection, opts={})
|
4
|
+
return if collection.blank?
|
5
|
+
|
6
|
+
html = []
|
7
|
+
collection.in_groups_of(count).each do |groups|
|
8
|
+
groups.compact.each do |obj|
|
9
|
+
html << capture do
|
10
|
+
content_tag :div, class: ["col-md-#{12/count.to_f.floor}", opts[:col_class]].compact.join(' ') do
|
11
|
+
yield obj
|
12
|
+
end
|
13
|
+
end.html_safe
|
14
|
+
end
|
15
|
+
end
|
16
|
+
concat html.join.html_safe
|
17
|
+
end
|
18
|
+
|
19
|
+
def row_groups_of(count, collection, opts={}, &block)
|
20
|
+
return if collection.blank?
|
21
|
+
|
22
|
+
html = []
|
23
|
+
subsetsize = (collection.count/count.to_f)
|
24
|
+
subsetsize.ceil.times do |i|
|
25
|
+
subset = collection[count*i...((count*i)+count)]
|
26
|
+
html << capture do
|
27
|
+
content_tag :div, class: ["row",opts[:row_class]].compact.join(' ') do
|
28
|
+
capture do
|
29
|
+
col_groups_of(count, subset, opts, &block)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end.html_safe
|
33
|
+
end
|
34
|
+
|
35
|
+
concat html.join.html_safe
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module MVP
|
2
|
+
module Slugification
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def slugify(name, opts={})
|
7
|
+
before_validation -> {
|
8
|
+
return true if self.slug.present?
|
9
|
+
self.slug = slugify(self.send(name.to_sym))
|
10
|
+
self.slug += "-#{SecureRandom.uuid}" if self.class.find_by(slug: self.slug).present?
|
11
|
+
}, opts
|
12
|
+
validates :slug, uniqueness: true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def slugify(str)
|
19
|
+
str.gsub(/[^a-zA-Z0-9]+/,'-')
|
20
|
+
.gsub(/^[-]+|[-]+$/,'')
|
21
|
+
.downcase
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
<% if ENV['ROLLBAR_CLIENT_ACCESS_TOKEN'] %>
|
2
|
+
<script>
|
3
|
+
var _rollbarConfig = {
|
4
|
+
accessToken: '<%= ENV['ROLLBAR_CLIENT_ACCESS_TOKEN'] %>',
|
5
|
+
captureUncaught: true,
|
6
|
+
captureUnhandledRejections: false,
|
7
|
+
payload: {
|
8
|
+
environment: "production"
|
9
|
+
}
|
10
|
+
};
|
11
|
+
// Rollbar Snippet
|
12
|
+
!function(r){function e(t){if(o[t])return o[t].exports;var n=o[t]={exports:{},id:t,loaded:!1};return r[t].call(n.exports,n,n.exports,e),n.loaded=!0,n.exports}var o={};return e.m=r,e.c=o,e.p="",e(0)}([function(r,e,o){"use strict";var t=o(1).Rollbar,n=o(2);_rollbarConfig.rollbarJsUrl=_rollbarConfig.rollbarJsUrl||"https://d37gvrvc0wt4s1.cloudfront.net/js/v1.9/rollbar.min.js";var a=t.init(window,_rollbarConfig),i=n(a,_rollbarConfig);a.loadFull(window,document,!_rollbarConfig.async,_rollbarConfig,i)},function(r,e){"use strict";function o(r){return function(){try{return r.apply(this,arguments)}catch(e){try{console.error("[Rollbar]: Internal error",e)}catch(o){}}}}function t(r,e,o){window._rollbarWrappedError&&(o[4]||(o[4]=window._rollbarWrappedError),o[5]||(o[5]=window._rollbarWrappedError._rollbarContext),window._rollbarWrappedError=null),r.uncaughtError.apply(r,o),e&&e.apply(window,o)}function n(r){var e=function(){var e=Array.prototype.slice.call(arguments,0);t(r,r._rollbarOldOnError,e)};return e.belongsToShim=!0,e}function a(r){this.shimId=++c,this.notifier=null,this.parentShim=r,this._rollbarOldOnError=null}function i(r){var e=a;return o(function(){if(this.notifier)return this.notifier[r].apply(this.notifier,arguments);var o=this,t="scope"===r;t&&(o=new e(this));var n=Array.prototype.slice.call(arguments,0),a={shim:o,method:r,args:n,ts:new Date};return window._rollbarShimQueue.push(a),t?o:void 0})}function l(r,e){if(e.hasOwnProperty&&e.hasOwnProperty("addEventListener")){var o=e.addEventListener;e.addEventListener=function(e,t,n){o.call(this,e,r.wrap(t),n)};var t=e.removeEventListener;e.removeEventListener=function(r,e,o){t.call(this,r,e&&e._wrapped?e._wrapped:e,o)}}}var c=0;a.init=function(r,e){var t=e.globalAlias||"Rollbar";if("object"==typeof r[t])return r[t];r._rollbarShimQueue=[],r._rollbarWrappedError=null,e=e||{};var i=new a;return o(function(){if(i.configure(e),e.captureUncaught){i._rollbarOldOnError=r.onerror,r.onerror=n(i);var o,a,c="EventTarget,Window,Node,ApplicationCache,AudioTrackList,ChannelMergerNode,CryptoOperation,EventSource,FileReader,HTMLUnknownElement,IDBDatabase,IDBRequest,IDBTransaction,KeyOperation,MediaController,MessagePort,ModalWindow,Notification,SVGElementInstance,Screen,TextTrack,TextTrackCue,TextTrackList,WebSocket,WebSocketWorker,Worker,XMLHttpRequest,XMLHttpRequestEventTarget,XMLHttpRequestUpload".split(",");for(o=0;o<c.length;++o)a=c[o],r[a]&&r[a].prototype&&l(i,r[a].prototype)}return e.captureUnhandledRejections&&(i._unhandledRejectionHandler=function(r){var e=r.reason,o=r.promise,t=r.detail;!e&&t&&(e=t.reason,o=t.promise),i.unhandledRejection(e,o)},r.addEventListener("unhandledrejection",i._unhandledRejectionHandler)),r[t]=i,i})()},a.prototype.loadFull=function(r,e,t,n,a){var i=function(){var e;if(void 0===r._rollbarPayloadQueue){var o,t,n,i;for(e=new Error("rollbar.js did not load");o=r._rollbarShimQueue.shift();)for(n=o.args,i=0;i<n.length;++i)if(t=n[i],"function"==typeof t){t(e);break}}"function"==typeof a&&a(e)},l=!1,c=e.createElement("script"),d=e.getElementsByTagName("script")[0],p=d.parentNode;c.crossOrigin="",c.src=n.rollbarJsUrl,c.async=!t,c.onload=c.onreadystatechange=o(function(){if(!(l||this.readyState&&"loaded"!==this.readyState&&"complete"!==this.readyState)){c.onload=c.onreadystatechange=null;try{p.removeChild(c)}catch(r){}l=!0,i()}}),p.insertBefore(c,d)},a.prototype.wrap=function(r,e){try{var o;if(o="function"==typeof e?e:function(){return e||{}},"function"!=typeof r)return r;if(r._isWrap)return r;if(!r._wrapped){r._wrapped=function(){try{return r.apply(this,arguments)}catch(e){throw e._rollbarContext=o()||{},e._rollbarContext._wrappedSource=r.toString(),window._rollbarWrappedError=e,e}},r._wrapped._isWrap=!0;for(var t in r)r.hasOwnProperty(t)&&(r._wrapped[t]=r[t])}return r._wrapped}catch(n){return r}};for(var d="log,debug,info,warn,warning,error,critical,global,configure,scope,uncaughtError,unhandledRejection".split(","),p=0;p<d.length;++p)a.prototype[d[p]]=i(d[p]);r.exports={Rollbar:a,_rollbarWindowOnError:t}},function(r,e){"use strict";r.exports=function(r,e){return function(o){if(!o&&!window._rollbarInitialized){var t=window.RollbarNotifier,n=e||{},a=n.globalAlias||"Rollbar",i=window.Rollbar.init(n,r);i._processShimQueue(window._rollbarShimQueue||[]),window[a]=i,window._rollbarInitialized=!0,t.processPayloads()}}}}]);
|
13
|
+
// End Rollbar Snippet
|
14
|
+
</script>
|
15
|
+
<% end %>
|
16
|
+
|
17
|
+
<% unless cookies[MVP::AnalyticsConcern::INVISIBLE_SESSION_COOKIE].to_b == true %>
|
18
|
+
<% if ENV['FACEBOOK_TRACKING_ID'] %>
|
19
|
+
<script>
|
20
|
+
!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
|
21
|
+
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
|
22
|
+
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
|
23
|
+
t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
|
24
|
+
document,'script','https://connect.facebook.net/en_US/fbevents.js');
|
25
|
+
|
26
|
+
fbq('init', '<%= ENV['FACEBOOK_TRACKING_ID'] %>');
|
27
|
+
fbq('track', "PageView");
|
28
|
+
<%= page.facebook_javascript.try(:html_safe) %>
|
29
|
+
</script>
|
30
|
+
<noscript><img height="1" width="1" style="display:none"
|
31
|
+
src="https://www.facebook.com/tr?id=<%= ENV['FACEBOOK_TRACKING_ID'] %>&ev=PageView&noscript=1"
|
32
|
+
/></noscript>
|
33
|
+
<!-- End Facebook Pixel Code -->
|
34
|
+
<% end %>
|
35
|
+
|
36
|
+
<% if ENV['SEGMENT_WRITE_KEY'] %>
|
37
|
+
<script type="text/javascript">
|
38
|
+
!function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","page","once","off","on"];analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};for(var t=0;t<analytics.methods.length;t++){var e=analytics.methods[t];analytics[e]=analytics.factory(e)}analytics.load=function(t){var e=document.createElement("script");e.type="text/javascript";e.async=!0;e.src=("https:"===document.location.protocol?"https://":"http://")+"cdn.segment.com/analytics.js/v1/"+t+"/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(e,n)};analytics.SNIPPET_VERSION="3.1.0";
|
39
|
+
analytics.load('<%= ENV['SEGMENT_WRITE_KEY'] %>');
|
40
|
+
|
41
|
+
<% analytics_identify_events.each do |event| %>
|
42
|
+
analytics.identify('<%= event['id'] %>', <%= event['properties'].to_json.html_safe %>);
|
43
|
+
<% end %>
|
44
|
+
<% analytics_track_events.each do |event| %>
|
45
|
+
analytics.track('<%= event['name'] %>', <%= event['properties'].to_json.html_safe %>);
|
46
|
+
<% end %>
|
47
|
+
|
48
|
+
analytics.page('<%= controller.controller_path %>.<%= controller.action_name %>', {
|
49
|
+
iteration: "<%= MVP::Iteration.version %>"
|
50
|
+
});
|
51
|
+
}}();
|
52
|
+
</script>
|
53
|
+
<% end %>
|
54
|
+
|
55
|
+
<% if ENV['GOOGLE_ANALYTICS_ID'] %>
|
56
|
+
<script>
|
57
|
+
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
58
|
+
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
59
|
+
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
60
|
+
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
61
|
+
ga('create', '<%= ENV['GOOGLE_ANALYTICS_ID'] %>', 'auto');
|
62
|
+
ga('send', 'pageview');
|
63
|
+
</script>
|
64
|
+
<% end %>
|
65
|
+
|
66
|
+
<% if ENV['HOTJAR_ID'] %>
|
67
|
+
<script>
|
68
|
+
(function(h,o,t,j,a,r){
|
69
|
+
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
|
70
|
+
h._hjSettings={hjid:<%= ENV['HOTJAR_ID'] %>,hjsv:5};
|
71
|
+
a=o.getElementsByTagName('head')[0];
|
72
|
+
r=o.createElement('script');r.async=1;
|
73
|
+
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
|
74
|
+
a.appendChild(r);
|
75
|
+
})(window,document,'//static.hotjar.com/c/hotjar-','.js?sv=');
|
76
|
+
</script>
|
77
|
+
<% end %>
|
78
|
+
|
79
|
+
<% if ENV['AMPLITUDE_API_KEY'] %>
|
80
|
+
<script type="text/javascript">
|
81
|
+
(function(e,t){var n=e.amplitude||{_q:[],_iq:{}};var r=t.createElement("script");r.type="text/javascript";
|
82
|
+
r.async=true;r.src="https://d24n15hnbwhuhn.cloudfront.net/libs/amplitude-3.0.1-min.gz.js";
|
83
|
+
r.onload=function(){e.amplitude.runQueuedFunctions()};var i=t.getElementsByTagName("script")[0];
|
84
|
+
i.parentNode.insertBefore(r,i);function s(e,t){e.prototype[t]=function(){this._q.push([t].concat(Array.prototype.slice.call(arguments,0)));
|
85
|
+
return this}}var o=function(){this._q=[];return this};var a=["add","append","clearAll","prepend","set","setOnce","unset"];
|
86
|
+
for(var u=0;u<a.length;u++){s(o,a[u])}n.Identify=o;var c=function(){this._q=[];return this;
|
87
|
+
};var p=["setProductId","setQuantity","setPrice","setRevenueType","setEventProperties"];
|
88
|
+
for(var l=0;l<p.length;l++){s(c,p[l])}n.Revenue=c;var d=["init","logEvent","logRevenue","setUserId","setUserProperties","setOptOut","setVersionName","setDomain","setDeviceId","setGlobalUserProperties","identify","clearUserProperties","setGroup","logRevenueV2","regenerateDeviceId"];
|
89
|
+
function v(e){function t(t){e[t]=function(){e._q.push([t].concat(Array.prototype.slice.call(arguments,0)));
|
90
|
+
}}for(var n=0;n<d.length;n++){t(d[n])}}v(n);n.getInstance=function(e){e=(!e||e.length===0?"$default_instance":e).toLowerCase();
|
91
|
+
if(!n._iq.hasOwnProperty(e)){n._iq[e]={_q:[]};v(n._iq[e])}return n._iq[e]};e.amplitude=n;
|
92
|
+
})(window,document);
|
93
|
+
|
94
|
+
amplitude.getInstance().init("<%= ENV['AMPLITUDE_API_KEY'] %>");
|
95
|
+
<% analytics_track_events.each do |event| %>
|
96
|
+
amplitude.getInstance().logEvent('<%= event['name'] %>', <%= event['properties'].to_json.html_safe %>);
|
97
|
+
<% end %>
|
98
|
+
</script>
|
99
|
+
<% end %>
|
100
|
+
<% end %>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<meta charset=utf-8>
|
2
|
+
<meta content="IE=edge" http-equiv=X-UA-Compatible>
|
3
|
+
<meta content="width=device-width,initial-scale=1" name=viewport>
|
4
|
+
<% if page.description %>
|
5
|
+
<meta content="<%= page.description %>" name="description">
|
6
|
+
<% end %>
|
7
|
+
<% if page.author %>
|
8
|
+
<meta content="<%= page.author %>" name="author">
|
9
|
+
<% end %>
|
10
|
+
<title><%= page.title %></title>
|
11
|
+
|
12
|
+
<% if page.canonical_url %>
|
13
|
+
<link rel="canonical" href="<%= page.canonical_url %>" />
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<% if page.noindex %>
|
17
|
+
<meta name="robots" content="noindex">
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
<% if page.og_url %>
|
21
|
+
<meta property="og:url" content="<%= page.og_url %>" />
|
22
|
+
<% end %>
|
23
|
+
<% if page.og_type %>
|
24
|
+
<meta property="og:type" content="<%= page.og_type %>" />
|
25
|
+
<% end %>
|
26
|
+
<% if page.og_title || page.title %>
|
27
|
+
<meta property="og:title" content="<%= page.og_title || page.title %>" />
|
28
|
+
<% end %>
|
29
|
+
<% if page.og_description || page.description %>
|
30
|
+
<meta property="og:description" content="<%= page.og_description || page.description %>" />
|
31
|
+
<% end %>
|
32
|
+
<% if page.og_image %>
|
33
|
+
<meta property="og:image" content="<%= page.og_image %>" />
|
34
|
+
<% end %>
|
35
|
+
<% if page.twitter_card %>
|
36
|
+
<meta name="twitter:card" content="<%= page.twitter_card %>" />
|
37
|
+
<% end %>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<!DOCTYPE HTML>
|
2
|
+
<html lang='en'>
|
3
|
+
<head>
|
4
|
+
<%= render('layouts/minimum_viable_product/meta').gsub(/\n/,'').html_safe %>
|
5
|
+
<%= yield :meta %>
|
6
|
+
<%= yield :stylesheets %>
|
7
|
+
<!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]-->
|
8
|
+
<%= yield :javascripts %>
|
9
|
+
<%= csrf_meta_tags %>
|
10
|
+
<%= render 'layouts/minimum_viable_product/instrumentation' %>
|
11
|
+
</head>
|
12
|
+
<body id="<%= body_id %>" class="<%= body_classes %>" data-controller="<%= controller.controller_path %>" data-action="<%= controller.action_name %>" data-iteration="<%= MVP::Iteration.version %>">
|
13
|
+
<% if content_for? :body %>
|
14
|
+
<%= yield :body %>
|
15
|
+
<% else %>
|
16
|
+
<%= yield %>
|
17
|
+
<% end %>
|
18
|
+
</body>
|
19
|
+
</html>
|
@@ -0,0 +1,191 @@
|
|
1
|
+
<div class="mb20">
|
2
|
+
<p class="mb10">
|
3
|
+
<button class="btn btn-default" type="button">Default</button>
|
4
|
+
<button class="btn btn-primary" type="button">Primary</button>
|
5
|
+
<button class="btn btn-success" type="button">Success</button>
|
6
|
+
<button class="btn btn-info" type="button">Info</button>
|
7
|
+
<button class="btn btn-warning" type="button">Warning</button>
|
8
|
+
<button class="btn btn-danger" type="button">Danger</button>
|
9
|
+
<button class="btn btn-link" type="button">Link</button>
|
10
|
+
</p>
|
11
|
+
|
12
|
+
<p class="mb10">
|
13
|
+
<button class="btn btn-primary btn-lg" type="button">Large button</button>
|
14
|
+
<button class="btn btn-default btn-lg" type="button">Large button</button>
|
15
|
+
</p>
|
16
|
+
<p class="mb10">
|
17
|
+
<button class="btn btn-primary" type="button">Default button</button>
|
18
|
+
<button class="btn btn-default" type="button">Default button</button>
|
19
|
+
</p>
|
20
|
+
<p class="mb10">
|
21
|
+
<button class="btn btn-primary btn-sm" type="button">Small button</button>
|
22
|
+
<button class="btn btn-default btn-sm" type="button">Small button</button>
|
23
|
+
</p>
|
24
|
+
<p class="mb10">
|
25
|
+
<button class="btn btn-primary btn-xs" type="button">Extra small button</button>
|
26
|
+
<button class="btn btn-default btn-xs" type="button">Extra small button</button>
|
27
|
+
</p>
|
28
|
+
</div>
|
29
|
+
|
30
|
+
<div class="mb20">
|
31
|
+
<div aria-label="Toolbar with button groups" class="btn-toolbar" role="toolbar">
|
32
|
+
<div aria-label="First group" class="btn-group" role="group">
|
33
|
+
<button class="btn btn-default" type="button">1</button>
|
34
|
+
<button class="btn btn-default" type="button">2</button>
|
35
|
+
<button class="btn btn-default" type="button">3</button>
|
36
|
+
<button class="btn btn-default" type="button">4</button>
|
37
|
+
</div>
|
38
|
+
<div aria-label="Second group" class="btn-group" role="group">
|
39
|
+
<button class="btn btn-default" type="button">5</button>
|
40
|
+
<button class="btn btn-default" type="button">6</button>
|
41
|
+
<button class="btn btn-default" type="button">7</button>
|
42
|
+
</div>
|
43
|
+
<div aria-label="Third group" class="btn-group" role="group">
|
44
|
+
<button class="btn btn-default" type="button">8</button>
|
45
|
+
</div>
|
46
|
+
</div>
|
47
|
+
</div>
|
48
|
+
|
49
|
+
<div class="mb20">
|
50
|
+
<div aria-label="Button group with nested dropdown" class="btn-group" role="group">
|
51
|
+
<button class="btn btn-default" type="button">1</button>
|
52
|
+
<button class="btn btn-default" type="button">2</button>
|
53
|
+
<div class="btn-group" role="group">
|
54
|
+
<button aria-expanded="false" aria-haspopup="true" class="btn btn-default dropdown-toggle" data-toggle="dropdown" id="btnGroupDrop1" type="button">
|
55
|
+
Dropdown
|
56
|
+
<span class="caret"></span>
|
57
|
+
</button>
|
58
|
+
<ul aria-labelledby="btnGroupDrop1" class="dropdown-menu">
|
59
|
+
<li>
|
60
|
+
<a href="#">Dropdown link</a>
|
61
|
+
</li>
|
62
|
+
<li>
|
63
|
+
<a href="#">Dropdown link</a>
|
64
|
+
</li>
|
65
|
+
</ul>
|
66
|
+
</div>
|
67
|
+
</div>
|
68
|
+
</div>
|
69
|
+
|
70
|
+
<div class="mb20">
|
71
|
+
<div class="btn-group">
|
72
|
+
<button aria-expanded="false" aria-haspopup="true" class="btn btn-default dropdown-toggle" data-toggle="dropdown" type="button">Default
|
73
|
+
<span class="caret"></span>
|
74
|
+
</button>
|
75
|
+
<ul class="dropdown-menu">
|
76
|
+
<li>
|
77
|
+
<a href="#">Action</a>
|
78
|
+
</li>
|
79
|
+
<li>
|
80
|
+
<a href="#">Another action</a>
|
81
|
+
</li>
|
82
|
+
<li>
|
83
|
+
<a href="#">Something else here</a>
|
84
|
+
</li>
|
85
|
+
<li class="divider" role="separator"></li>
|
86
|
+
<li>
|
87
|
+
<a href="#">Separated link</a>
|
88
|
+
</li>
|
89
|
+
</ul>
|
90
|
+
</div>
|
91
|
+
<div class="btn-group">
|
92
|
+
<button aria-expanded="false" aria-haspopup="true" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" type="button">Primary
|
93
|
+
<span class="caret"></span>
|
94
|
+
</button>
|
95
|
+
<ul class="dropdown-menu">
|
96
|
+
<li>
|
97
|
+
<a href="#">Action</a>
|
98
|
+
</li>
|
99
|
+
<li>
|
100
|
+
<a href="#">Another action</a>
|
101
|
+
</li>
|
102
|
+
<li>
|
103
|
+
<a href="#">Something else here</a>
|
104
|
+
</li>
|
105
|
+
<li class="divider" role="separator"></li>
|
106
|
+
<li>
|
107
|
+
<a href="#">Separated link</a>
|
108
|
+
</li>
|
109
|
+
</ul>
|
110
|
+
</div>
|
111
|
+
<div class="btn-group">
|
112
|
+
<button aria-expanded="false" aria-haspopup="true" class="btn btn-success dropdown-toggle" data-toggle="dropdown" type="button">Success
|
113
|
+
<span class="caret"></span>
|
114
|
+
</button>
|
115
|
+
<ul class="dropdown-menu">
|
116
|
+
<li>
|
117
|
+
<a href="#">Action</a>
|
118
|
+
</li>
|
119
|
+
<li>
|
120
|
+
<a href="#">Another action</a>
|
121
|
+
</li>
|
122
|
+
<li>
|
123
|
+
<a href="#">Something else here</a>
|
124
|
+
</li>
|
125
|
+
<li class="divider" role="separator"></li>
|
126
|
+
<li>
|
127
|
+
<a href="#">Separated link</a>
|
128
|
+
</li>
|
129
|
+
</ul>
|
130
|
+
</div>
|
131
|
+
<div class="btn-group">
|
132
|
+
<button aria-expanded="false" aria-haspopup="true" class="btn btn-info dropdown-toggle" data-toggle="dropdown" type="button">Info
|
133
|
+
<span class="caret"></span>
|
134
|
+
</button>
|
135
|
+
<ul class="dropdown-menu">
|
136
|
+
<li>
|
137
|
+
<a href="#">Action</a>
|
138
|
+
</li>
|
139
|
+
<li>
|
140
|
+
<a href="#">Another action</a>
|
141
|
+
</li>
|
142
|
+
<li>
|
143
|
+
<a href="#">Something else here</a>
|
144
|
+
</li>
|
145
|
+
<li class="divider" role="separator"></li>
|
146
|
+
<li>
|
147
|
+
<a href="#">Separated link</a>
|
148
|
+
</li>
|
149
|
+
</ul>
|
150
|
+
</div>
|
151
|
+
<div class="btn-group">
|
152
|
+
<button aria-expanded="false" aria-haspopup="true" class="btn btn-warning dropdown-toggle" data-toggle="dropdown" type="button">Warning
|
153
|
+
<span class="caret"></span>
|
154
|
+
</button>
|
155
|
+
<ul class="dropdown-menu">
|
156
|
+
<li>
|
157
|
+
<a href="#">Action</a>
|
158
|
+
</li>
|
159
|
+
<li>
|
160
|
+
<a href="#">Another action</a>
|
161
|
+
</li>
|
162
|
+
<li>
|
163
|
+
<a href="#">Something else here</a>
|
164
|
+
</li>
|
165
|
+
<li class="divider" role="separator"></li>
|
166
|
+
<li>
|
167
|
+
<a href="#">Separated link</a>
|
168
|
+
</li>
|
169
|
+
</ul>
|
170
|
+
</div>
|
171
|
+
<div class="btn-group">
|
172
|
+
<button aria-expanded="false" aria-haspopup="true" class="btn btn-danger dropdown-toggle" data-toggle="dropdown" type="button">Danger
|
173
|
+
<span class="caret"></span>
|
174
|
+
</button>
|
175
|
+
<ul class="dropdown-menu">
|
176
|
+
<li>
|
177
|
+
<a href="#">Action</a>
|
178
|
+
</li>
|
179
|
+
<li>
|
180
|
+
<a href="#">Another action</a>
|
181
|
+
</li>
|
182
|
+
<li>
|
183
|
+
<a href="#">Something else here</a>
|
184
|
+
</li>
|
185
|
+
<li class="divider" role="separator"></li>
|
186
|
+
<li>
|
187
|
+
<a href="#">Separated link</a>
|
188
|
+
</li>
|
189
|
+
</ul>
|
190
|
+
</div>
|
191
|
+
</div>
|