mvpkit 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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>