mvpkit 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +30 -0
  3. data/Gemfile.lock +329 -0
  4. data/LICENSE.txt +20 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +134 -0
  7. data/Rakefile +52 -0
  8. data/VERSION +1 -0
  9. data/app/assets/javascripts/mvp/application.js +1 -0
  10. data/app/assets/stylesheets/mvp/application.scss +0 -0
  11. data/app/controllers/concerns/mvp/analytics_concern.rb +78 -0
  12. data/app/controllers/concerns/mvp/seo_concern.rb +25 -0
  13. data/app/controllers/concerns/mvp/session_concern.rb +44 -0
  14. data/app/controllers/mvp/analytics_controller.rb +12 -0
  15. data/app/controllers/mvp/seo_controller.rb +11 -0
  16. data/app/controllers/mvp/styleguide_controller.rb +23 -0
  17. data/app/helpers/minimum_viable_product/body_helper.rb +14 -0
  18. data/app/helpers/minimum_viable_product/bootstrap_helper.rb +38 -0
  19. data/app/helpers/minimum_viable_product/styleguide_helper.rb +4 -0
  20. data/app/models/concerns/mvp/slugification.rb +24 -0
  21. data/app/views/layouts/minimum_viable_product/_instrumentation.html.erb +100 -0
  22. data/app/views/layouts/minimum_viable_product/_meta.html.erb +37 -0
  23. data/app/views/layouts/minimum_viable_product/application.html.erb +19 -0
  24. data/app/views/minimum_viable_product/styleguide/_example.html.erb +6 -0
  25. data/app/views/minimum_viable_product/styleguide/bootstrap/_buttons.html.erb +191 -0
  26. data/app/views/minimum_viable_product/styleguide/bootstrap/_forms.html.erb +192 -0
  27. data/app/views/minimum_viable_product/styleguide/bootstrap/_header.html.erb +48 -0
  28. data/app/views/minimum_viable_product/styleguide/bootstrap/_panels.html.erb +16 -0
  29. data/app/views/minimum_viable_product/styleguide/bootstrap/_tables.html.erb +34 -0
  30. data/app/views/minimum_viable_product/styleguide/bootstrap/_typography.html.erb +51 -0
  31. data/app/views/minimum_viable_product/styleguide/bootstrap.html.erb +43 -0
  32. data/app/views/minimum_viable_product/styleguide/elements/_grouping.html.erb +1 -0
  33. data/app/views/minimum_viable_product/styleguide/elements/partials/_row_groups_of.html.erb +7 -0
  34. data/app/views/minimum_viable_product/styleguide/index.html.erb +17 -0
  35. data/app/views/minimum_viable_product/styleguide/layouts/basic.html.erb +4 -0
  36. data/app/views/minimum_viable_product/styleguide/layouts/carousel.html.erb +120 -0
  37. data/app/views/minimum_viable_product/styleguide/layouts/cover.html.erb +34 -0
  38. data/assets/js/application.js +31 -0
  39. data/assets/js/init/controllers.js +26 -0
  40. data/assets/js/init/forms.js +12 -0
  41. data/bin/mvp +78 -0
  42. data/bin/rails +12 -0
  43. data/config/initializers/assets.rb +2 -0
  44. data/config/initializers/canonical_host.rb +3 -0
  45. data/config/initializers/cloudinary.rb +7 -0
  46. data/config/initializers/geocoder.rb +9 -0
  47. data/config/initializers/iteration.rb +33 -0
  48. data/config/initializers/project.rb +1 -0
  49. data/config/initializers/rollbar.rb +59 -0
  50. data/config/initializers/routing.rb +7 -0
  51. data/config/initializers/spoof_ip.rb +33 -0
  52. data/config/initializers/ssl.rb +14 -0
  53. data/config/routes.rb +6 -0
  54. data/lib/mvp/engine.rb +22 -0
  55. data/lib/mvp/ext/nil.rb +5 -0
  56. data/lib/mvp/ext/string.rb +7 -0
  57. data/lib/mvpkit.rb +6 -0
  58. data/lib/tasks/sitemap.rake +42 -0
  59. data/mvpkit.gemspec +245 -0
  60. data/package.json +43 -0
  61. data/project/.gitignore +45 -0
  62. data/project/Gemfile +33 -0
  63. data/project/Gemfile.lock +437 -0
  64. data/project/Procfile +2 -0
  65. data/project/README.md +117 -0
  66. data/project/Rakefile +14 -0
  67. data/project/app/controllers/application_controller.rb +12 -0
  68. data/project/app/controllers/conversions_controller.rb +24 -0
  69. data/project/app/controllers/examples_controller.rb +2 -0
  70. data/project/app/controllers/home_controller.rb +7 -0
  71. data/project/app/decorators/.keep +0 -0
  72. data/project/app/helpers/application_helper.rb +24 -0
  73. data/project/app/mailers/.keep +0 -0
  74. data/project/app/models/conversion.rb +4 -0
  75. data/project/app/views/examples/index.html.erb +1 -0
  76. data/project/app/views/examples/mustache/template.mustache +1 -0
  77. data/project/app/views/examples/mustache.html.erb +18 -0
  78. data/project/app/views/home/conversion.html.erb +12 -0
  79. data/project/app/views/home/index.html.erb +28 -0
  80. data/project/app/views/layouts/_header.html.erb +16 -0
  81. data/project/app/views/layouts/_includes.html.erb +7 -0
  82. data/project/app/views/layouts/application.html.erb +17 -0
  83. data/project/app/views/layouts/modal.html.erb +14 -0
  84. data/project/assets/images/.keep +0 -0
  85. data/project/assets/images/favicon.ico +0 -0
  86. data/project/assets/javascripts/controllers/home.coffee +15 -0
  87. data/project/assets/javascripts/pack.js +9 -0
  88. data/project/assets/stylesheets/config/variables.scss +876 -0
  89. data/project/assets/stylesheets/layout/basic.scss +6 -0
  90. data/project/assets/stylesheets/layout/carousel.scss +127 -0
  91. data/project/assets/stylesheets/layout/cover.scss +129 -0
  92. data/project/assets/stylesheets/lib/spacing.scss +55 -0
  93. data/project/assets/stylesheets/skin/style.scss +16 -0
  94. data/project/assets/stylesheets/style.scss +8 -0
  95. data/project/bin/bundle +3 -0
  96. data/project/bin/rails +9 -0
  97. data/project/bin/rake +9 -0
  98. data/project/bin/setup +32 -0
  99. data/project/bin/spring +15 -0
  100. data/project/config/application.rb +32 -0
  101. data/project/config/boot.rb +3 -0
  102. data/project/config/database.yml +19 -0
  103. data/project/config/environment.rb +5 -0
  104. data/project/config/environments/development.rb +67 -0
  105. data/project/config/environments/production.rb +93 -0
  106. data/project/config/environments/test.rb +42 -0
  107. data/project/config/initializers/assets.rb +11 -0
  108. data/project/config/initializers/backtrace_silencers.rb +7 -0
  109. data/project/config/initializers/cookies_serializer.rb +3 -0
  110. data/project/config/initializers/filter_parameter_logging.rb +4 -0
  111. data/project/config/initializers/inflections.rb +16 -0
  112. data/project/config/initializers/mime_types.rb +4 -0
  113. data/project/config/initializers/mustache.rb +7 -0
  114. data/project/config/initializers/rails_admin.rb +43 -0
  115. data/project/config/initializers/session_store.rb +3 -0
  116. data/project/config/initializers/simple_form.rb +177 -0
  117. data/project/config/initializers/wrap_parameters.rb +14 -0
  118. data/project/config/locales/en.yml +23 -0
  119. data/project/config/locales/simple_form.en.yml +31 -0
  120. data/project/config/routes.rb +13 -0
  121. data/project/config/secrets.yml +8 -0
  122. data/project/config/sitemap.rb +28 -0
  123. data/project/config.ru +4 -0
  124. data/project/db/migrate/20160728235100_create_conversions.rb +9 -0
  125. data/project/db/schema.rb +25 -0
  126. data/project/db/seeds.rb +7 -0
  127. data/project/lib/assets/.keep +0 -0
  128. data/project/lib/tasks/heroku.rake +70 -0
  129. data/project/log/.keep +0 -0
  130. data/project/log/development.log +48216 -0
  131. data/project/log/production.log +0 -0
  132. data/project/package.json +44 -0
  133. data/project/public/404.html +67 -0
  134. data/project/public/422.html +67 -0
  135. data/project/public/500.html +66 -0
  136. data/project/public/assets/javascripts/448c34a56d699c29117adc64c43affeb.woff2 +0 -0
  137. data/project/public/assets/javascripts/89889688147bd7575d6327160d64e760.svg +288 -0
  138. data/project/public/assets/javascripts/e18bbf611f2a2e43afc071aa2f4e1512.ttf +0 -0
  139. data/project/public/assets/javascripts/f4769f9bdb7466be65088239c12046d1.eot +0 -0
  140. data/project/public/assets/javascripts/fa2772327f55d8198301fdb8bcfc8158.woff +0 -0
  141. data/project/public/assets/javascripts/pack.js +31367 -0
  142. data/project/public/assets/javascripts/pack.js.map +1 -0
  143. data/project/public/assets/pack.js +17220 -0
  144. data/project/public/assets/style.css +7477 -0
  145. data/project/vendor/assets/javascripts/.keep +0 -0
  146. data/project/vendor/assets/stylesheets/.keep +0 -0
  147. data/project/webpack.config.js +67 -0
  148. data/test/helper.rb +34 -0
  149. data/test/test_minimum_viable_product.rb +7 -0
  150. 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,12 @@
1
+ module MinimumViableProduct
2
+ class AnalyticsController < ActionController::Base
3
+ def optout
4
+ cookies[AnalyticsConcern::INVISIBLE_SESSION_COOKIE] = {
5
+ :value => true,
6
+ :expires => 1.year.from_now,
7
+ }
8
+
9
+ redirect_to root_path
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module MinimumViableProduct
2
+ class SeoController < ActionController::Base
3
+ def robots
4
+ render text: %%
5
+ User-agent: *
6
+ Disallow:
7
+ Sitemap: #{MVP::Engine.routes.url_helpers.sitemap_url}
8
+ %, content_type: "text/plain"
9
+ end
10
+ end
11
+ 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,4 @@
1
+ module MinimumViableProduct
2
+ module StyleguideHelper
3
+ end
4
+ 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,6 @@
1
+
2
+ <%= render "minimum_viable_product/styleguide/elements/partials/#{source}" %>
3
+
4
+ <pre>
5
+ <%= File.open(File.join(MinimumViableProduct::Engine.root,'app/views/minimum_viable_product/styleguide/elements/partials/',"_#{source}.html.erb")).read.strip %>
6
+ </pre>
@@ -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>