disco_app 0.6.1 → 0.6.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a29063430cb2904c29bf74567496355a5f70d5e4e5d942d8f9ad8341ee99f935
4
- data.tar.gz: c1ad2a5cf842f792213ef025f948057132bfdede2c78945d965edc925ad3f62f
3
+ metadata.gz: f6bcc38c1a00ea30bb3a0fe0a319b7fbedb26c3e022247a8e2cd5bac114459a4
4
+ data.tar.gz: f5b6885baebbeea7b2d5173803822a175bad1be09b2e65db1d8e0376e1fbf306
5
5
  SHA512:
6
- metadata.gz: 6dd9ac41a62be53b26c1ab0d7aa30d0078a1adbc0ae7cb5342567bca85764da13eba2b6a3cb5dbcfc4867dd8ea7e433811eaa9131549d85a43b2d75fe7a09a89
7
- data.tar.gz: 2c06d93aaae37aa4d52b39ae35727e0ebf1bfd9c86f252bbd9bb910e61088c74aaba02037675b8da29beb50b4a8f485ba8f54ac9f0a508c88cb1b2cc05fcb8bc
6
+ metadata.gz: d9bb6a2e5e899768eb3954830140a73adf764275eb9e8f7e1635b6a32e7596b1bfbe0f77591c62e7845f2f640904651d81fe5f6606a358ecfe64ee55149c47dd
7
+ data.tar.gz: ae895af6f73f42668c2d6b9b2458a81481194becd38d4f9c44e30560a7905d7e8e3d12fff6a5806e18beb3b4082e020a28c95361f356c0ab7df6e54487da0b82
@@ -4,4 +4,4 @@
4
4
  * Assumes that jQuery will be loaded in the parent application.js.
5
5
  */
6
6
  //= require bootstrap-sprockets
7
- //= require_tree .
7
+ //= require disco_app/shopify-turbolinks
@@ -0,0 +1,152 @@
1
+ /**
2
+ * frame.js
3
+ *
4
+ * The FrameApp object is a lightweight Javascript object intended to mock the `postMessage` endpoint for Embedded Apps
5
+ * in the Shopify Admin panel. Eventually, we hope to mock all of the functionality provided by the Shopify Embedded App
6
+ * SDK.
7
+ */
8
+ (function() {
9
+
10
+ window.FrameApp = (function() {
11
+
12
+ FrameApp.name = 'Shopify Dev Frame';
13
+
14
+ function FrameApp() {}
15
+
16
+
17
+ /* Initialisation, configuration and helpers.
18
+ ================================================== */
19
+
20
+ /**
21
+ * Initialise the FrameApp - load configuration, set up event handlers.
22
+ *
23
+ * @param config
24
+ * @returns {*}
25
+ */
26
+ FrameApp.init = function(config) {
27
+ var _this = this;
28
+ if (config == null) {
29
+ config = {};
30
+ }
31
+ this.loadConfig(config);
32
+
33
+ // Use addEventListener if available, otherwise fall back to attachEvent.
34
+ if (window.addEventListener) {
35
+ this.iframe.addEventListener("load", FrameApp.__iframeLoadCallback, false);
36
+ return window.addEventListener("message", FrameApp.__addEventMessageCallback, false);
37
+ }
38
+
39
+ this.iframe.attachEvent("load", FrameApp.__iframeLoadCallback);
40
+ return window.attachEvent("onMessage", FrameApp.__addEventMessageCallback);
41
+ };
42
+
43
+ /**
44
+ * Load configuration for the FrameApp. Set defaults if not provided.
45
+ * @param config
46
+ */
47
+ FrameApp.loadConfig = function(config) {
48
+ this.shopOrigin = config.shopOrigin;
49
+ this.debug = !!config.debug;
50
+ this.iframe = config.iframe;
51
+ if (!this.iframe) {
52
+ this.log("FrameApp error: no <iframe> specified.");
53
+ }
54
+ FrameApp.log('FrameApp configuration loaded.');
55
+ };
56
+
57
+ /**
58
+ * Log a message to the console, if the app was configured in debug mode.
59
+ *
60
+ * @param message
61
+ * @param force
62
+ * @returns {*}
63
+ */
64
+ FrameApp.log = function(message, force) {
65
+ if ((typeof console !== "undefined" && console !== null ? console.log : void 0) && (this.debug || force)) {
66
+ return console.log(message);
67
+ }
68
+ };
69
+
70
+
71
+ /* Message sending and event handling.
72
+ ================================================== */
73
+
74
+ FrameApp.__messageHandlers = {};
75
+
76
+ /**
77
+ * Post a message to the <iframe>.
78
+ *
79
+ * @param message
80
+ * @param data
81
+ * @returns {*}
82
+ */
83
+ FrameApp.postMessage = function(message, data) {
84
+ var json;
85
+ json = JSON.stringify({
86
+ message: message,
87
+ data: data
88
+ });
89
+ FrameApp.log("FrameApp client sent " + json + " to ShopifyApp.");
90
+ return this.iframe.contentWindow.postMessage(json, '*');
91
+ };
92
+
93
+ /**
94
+ * Add a handler for a received message.
95
+ *
96
+ * @param message
97
+ * @param fn
98
+ * @returns {Number|*}
99
+ * @private
100
+ */
101
+ FrameApp.__addMessageHandler = function(message, fn) {
102
+ if (typeof message === "function") {
103
+ fn = message;
104
+ message = void 0;
105
+ }
106
+ if (!FrameApp.__messageHandlers[message]) {
107
+ FrameApp.__messageHandlers[message] = [];
108
+ }
109
+ return FrameApp.__messageHandlers[message].push(fn);
110
+ };
111
+
112
+ /**
113
+ * Callback triggered when a postMessage message is received.
114
+ *
115
+ * @param e
116
+ * @returns {*}
117
+ * @private
118
+ */
119
+ FrameApp.__addEventMessageCallback = function(e) {
120
+ var handler, handlers, message, submitForm, _i, _len;
121
+ FrameApp.log("FrameApp client received " + e.data + " from " + e.origin);
122
+ message = JSON.parse(e.data);
123
+ handlers = [];
124
+ if (FrameApp.__messageHandlers[message.message]) {
125
+ handlers = handlers.concat(FrameApp.__messageHandlers[message.message]);
126
+ }
127
+ if (FrameApp.__messageHandlers[void 0]) {
128
+ handlers = handlers.concat(FrameApp.__messageHandlers[void 0]);
129
+ }
130
+ for (_i = 0, _len = handlers.length; _i < _len; _i++) {
131
+ handler = handlers[_i];
132
+ handler(message.message, message.data);
133
+ }
134
+ };
135
+
136
+ /**
137
+ * Callback triggered when our iFrame is loaded.
138
+ *
139
+ * @param e
140
+ * @private
141
+ */
142
+ FrameApp.__iframeLoadCallback = function(e) {
143
+ FrameApp.postMessage('Shopify.API.initialize', {
144
+ 'hi': 'there!'
145
+ });
146
+ };
147
+
148
+ return FrameApp;
149
+
150
+ }).call(this);
151
+
152
+ }).call(this);
@@ -0,0 +1,7 @@
1
+ /**
2
+ * disco_app/shopify-turbolinks.js
3
+ * Some tweaks to help Turbolinks play nicely with the Embedded App SDK.
4
+ */
5
+ jQuery(document).on('page:load', function(e) {
6
+ ShopifyApp.pushState(window.location.pathname);
7
+ });
@@ -329,7 +329,7 @@ $screen-md-max: ($screen-lg-min - 1) !default;
329
329
  //** Number of columns in the grid.
330
330
  $grid-columns: 24;
331
331
  //** Padding between columns. Gets divided in half for the left and right.
332
- $grid-gutter-width: 12px;
332
+ $grid-gutter-width: 20px;
333
333
  // Navbar collapse
334
334
  //** Point at which the navbar becomes uncollapsed.
335
335
  $grid-float-breakpoint: $screen-sm-min !default;
@@ -30,6 +30,14 @@
30
30
  padding: 20px;
31
31
  }
32
32
 
33
+ .next-card__section ~ .next-card__section {
34
+ border-top: 1px solid #ebeef0;
35
+ }
36
+
37
+ .next-card__section--no-bottom-padding {
38
+ padding-bottom: 0;
39
+ }
40
+
33
41
  .next-card--aside,
34
42
  .next-card--disabled {
35
43
  background-color: #f5f6f7;
@@ -0,0 +1,53 @@
1
+ //
2
+ // Replicate the styles for Shopify Admin tabs.
3
+ // --------------------------------------------------
4
+
5
+ .next-tab__list {
6
+ padding: 0;
7
+ margin: 0;
8
+ list-style: none;
9
+ background-color: #f5f6f7;
10
+ overflow: visible;
11
+ border-radius: 3px 3px 0 0;
12
+
13
+ flex-wrap: nowrap;
14
+ display: flex;
15
+ align-items: stretch;
16
+
17
+ > li {
18
+ position: relative;
19
+ flex-grow: 0;
20
+ flex-shrink: 0;
21
+ display: flex;
22
+ align-items: stretch;
23
+
24
+ &:first-child .next-tab {
25
+ border-top-left-radius: 3px;
26
+ }
27
+ }
28
+ }
29
+
30
+ .next-tab {
31
+ padding: 15px 20px;
32
+ text-decoration: none;
33
+ color: #798c9c;
34
+ border-right: 1px solid #ebeef0;
35
+ border-bottom: 1px solid #ebeef0;
36
+ text-align: center;
37
+ line-height: 1;
38
+ cursor: pointer;
39
+ position: relative;
40
+ font-size: 13px;
41
+ flex-grow: 1;
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+
46
+ &.next-tab--is-active {
47
+ background-color: #ffffff;
48
+ color: #31373d;
49
+ border-bottom-color: #ffffff;
50
+ cursor: default;
51
+ text-decoration: none;
52
+ }
53
+ }
@@ -11,3 +11,4 @@
11
11
  @import 'disco/cards';
12
12
  @import 'disco/buttons';
13
13
  @import 'disco/forms';
14
+ @import 'disco/tabs';
@@ -0,0 +1,54 @@
1
+ //
2
+ // Buttons
3
+ // --------------------------------------------------
4
+
5
+ // Base button
6
+ .btn {
7
+ cursor: pointer;
8
+ display: inline-block;
9
+ height: 32px;
10
+ line-height: 30px;
11
+ padding: 0 9px;
12
+ border-radius: 4px;
13
+
14
+ white-space: nowrap;
15
+ vertical-align: middle;
16
+ font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
17
+ font-size: 13px;
18
+
19
+ -webkit-user-select: none;
20
+ -moz-user-select: none;
21
+ -o-user-select: none;
22
+ user-select: none;
23
+ -webkit-appearance: none;
24
+
25
+ &:hover {
26
+ text-decoration: none;
27
+ }
28
+ }
29
+
30
+ // Default button
31
+ .btn, .btn-default {
32
+ background-color: #fcfcfc;
33
+ border: 1px solid #e3e3e3;
34
+ color: #479ccf;
35
+
36
+ &:hover, &:focus, &.focus {
37
+ background-color: #efefef;
38
+ border-color: #d6d6d6;
39
+ color: #479ccf;
40
+ }
41
+ }
42
+
43
+ // Primary button
44
+ .btn-primary {
45
+ background-color: #479ccf;
46
+ border: 1px solid #2f82b4;
47
+ color: #fff;
48
+
49
+ &:hover, &:focus, &.focus {
50
+ background-color: #3491c8;
51
+ border-color: #2a74a0;
52
+ color: #fff;
53
+ }
54
+ }
@@ -0,0 +1,26 @@
1
+ //
2
+ // Forms
3
+ // --------------------------------------------------
4
+
5
+ form {
6
+ margin: 40px 0;
7
+ }
8
+
9
+ input[type="text"],
10
+ input[type="url"], {
11
+ vertical-align: top;
12
+ height: 32px;
13
+ font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
14
+ font-size: 13px;
15
+ padding: 5px;
16
+ margin: 0;
17
+ border: 1px solid #ccc;
18
+ display: inline-block;
19
+ color: #222;
20
+ border-radius: 4px;
21
+
22
+ &:focus, &.focus {
23
+ border: 1px solid #479ccf;
24
+ outline: 0;
25
+ }
26
+ }
@@ -0,0 +1,77 @@
1
+ //
2
+ // Layout
3
+ // --------------------------------------------------
4
+
5
+ * {
6
+ -webkit-box-sizing: border-box;
7
+ -moz-box-sizing: border-box;
8
+ box-sizing: border-box;
9
+ }
10
+
11
+ #sidebar {
12
+ position: absolute;
13
+ top: 0;
14
+ left: 0;
15
+ bottom: 0;
16
+ width: $sidebar-width;
17
+
18
+ background: #31373d;
19
+ box-shadow: -1px 0 0 #2b3136 inset;
20
+ }
21
+
22
+ #header {
23
+ position: absolute;
24
+ top: 0;
25
+ left: $sidebar-width;
26
+ right: 0;
27
+ height: $header-height;
28
+
29
+ background: #ffffff;
30
+ border-bottom: 1px solid #e6e6e6;
31
+ border-color: rgba(0,0,0, .07);
32
+ }
33
+
34
+ #header-title {
35
+ position: absolute;
36
+ bottom: 12px;
37
+ left: 20px;
38
+
39
+ max-width: 718px;
40
+ white-space: nowrap;
41
+ text-overflow: ellipsis;
42
+ overflow: hidden;
43
+ }
44
+
45
+ #header-title-icon {
46
+ margin: 5px 10px 0 0;
47
+ float: left;
48
+ }
49
+
50
+ #header-actions {
51
+ position: absolute;
52
+ bottom: 12px;
53
+ right: 20px;
54
+
55
+ .btn {
56
+ margin: 0 0 0 5px;
57
+ }
58
+ }
59
+
60
+ #content-wrapper {
61
+ position: absolute;
62
+ top: $header-height;
63
+ left: $sidebar-width;
64
+ bottom: 0;
65
+ right: 0;
66
+ }
67
+
68
+ #content {
69
+ width: 100%;
70
+ height: 100%;
71
+ border: none;
72
+ }
73
+
74
+ #iframe {
75
+ padding: 40px 0;
76
+ text-align: center;
77
+ }
@@ -0,0 +1,32 @@
1
+ //
2
+ // Type
3
+ // --------------------------------------------------
4
+
5
+ @font-face {
6
+ font-family: 'ProximaNovaLight';
7
+ src: local('ProximaNovaLight'), local('ProximaNova-Light');
8
+ font-weight: normal;
9
+ font-style: normal;
10
+ }
11
+
12
+ // Base
13
+ html, body {
14
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
15
+ font-size: 13px;
16
+ }
17
+
18
+ // Headers
19
+ h1 {
20
+ font-size: 24px;
21
+ line-height: 32px;
22
+ height: 32px;
23
+ font-family: ProximaNovaLight,"Helvetica Neue",Helvetica,Arial,sans-serif;
24
+ font-weight: 300;
25
+ margin: 0;
26
+ padding: 0;
27
+ }
28
+
29
+ // Text utilities
30
+ .text-muted {
31
+ color: #ccc;
32
+ }
@@ -0,0 +1,9 @@
1
+ // Set variables
2
+ $sidebar-width: 197px;
3
+ $header-height: 57px;
4
+
5
+ // Include components
6
+ @import "frame/layout";
7
+ @import "frame/type";
8
+ @import "frame/buttons";
9
+ @import "frame/forms";
@@ -0,0 +1,9 @@
1
+ class DiscoApp::FrameController < ActionController::Base
2
+
3
+ layout nil
4
+
5
+ def frame
6
+
7
+ end
8
+
9
+ end
@@ -1,4 +1,9 @@
1
- module DiscoApp
2
- module ApplicationHelper
1
+ module DiscoApp::ApplicationHelper
2
+
3
+ def link_to_shopify_admin(shop, name, admin_path, options = {})
4
+ options[:onclick] = "ShopifyApp.redirect('#{admin_path}'); return false;"
5
+ options[:'data-no-turbolink'] = true
6
+ link_to(name, "https://#{shop.shopify_domain}/admin/#{admin_path}", options)
3
7
  end
8
+
4
9
  end
@@ -0,0 +1,36 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dev Frame</title>
5
+ <%= stylesheet_link_tag 'disco_app/frame', media: 'all' %>
6
+ <%= javascript_include_tag 'disco_app/frame' %>
7
+ </head>
8
+ <body>
9
+ <!-- Left Sidebar -->
10
+ <aside id="sidebar"></aside>
11
+
12
+ <!-- Header Bar -->
13
+ <header id="header">
14
+ <h1 id="header-title">
15
+ <img id="header-title-icon" src="<%= image_path('disco_app/icon.svg') %>" width="20" height="20" />
16
+ Shopify Dev Frame
17
+ </h1>
18
+ <div id="header-actions">
19
+ <!-- No action. -->
20
+ </div>
21
+ </header>
22
+
23
+ <!-- Content iFrame -->
24
+ <section id="content-wrapper">
25
+ <iframe id="content" src="/"></iframe>
26
+ </section>
27
+
28
+ <!-- Setup FrameApp. -->
29
+ <script type="text/javascript">
30
+ FrameApp.init({
31
+ debug: true,
32
+ iframe: document.getElementById('content')
33
+ });
34
+ </script>
35
+ </body>
36
+ </html>
@@ -5,9 +5,7 @@
5
5
  <%= content_for :card_header %>
6
6
  </header>
7
7
  <% end %>
8
- <section class="next-card__section">
9
- <%= content_for :card_content %>
10
- </section>
8
+ <%= content_for :card_content %>
11
9
  <% if content_for?(:card_footer) %>
12
10
  <footer class="next-card__footer">
13
11
  <%= content_for :card_footer %>
@@ -36,6 +36,6 @@
36
36
  </script>
37
37
  <% end %>
38
38
 
39
- <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
39
+ <%= javascript_include_tag 'application', 'data-turbolinks-track' => true, 'data-turbolinks-eval' => false %>
40
40
  </body>
41
41
  </html>
data/config/routes.rb CHANGED
@@ -16,4 +16,11 @@ DiscoApp::Engine.routes.draw do
16
16
  get 'uninstalling' => :uninstalling, as: :uninstalling
17
17
  end
18
18
 
19
+ # Make the embedded app frame emulator available in development.
20
+ if Rails.env.development?
21
+ controller :frame do
22
+ get 'frame' => :frame, as: :frame
23
+ end
24
+ end
25
+
19
26
  end
@@ -5,7 +5,19 @@ require 'turbolinks'
5
5
 
6
6
  module DiscoApp
7
7
  class Engine < ::Rails::Engine
8
+
8
9
  isolate_namespace DiscoApp
9
10
  engine_name 'disco_app'
11
+
12
+ # Ensure DiscoApp helpers are available throughout application.
13
+ config.to_prepare do
14
+ ApplicationController.helper(DiscoApp::ApplicationHelper)
15
+ end
16
+
17
+ # Ensure our frame assets are included for precompilation.
18
+ initializer 'disco_app.assets.precompile' do |app|
19
+ app.config.assets.precompile += %w(disco_app/frame.css disco_app/frame.js)
20
+ end
21
+
10
22
  end
11
23
  end
@@ -1,3 +1,3 @@
1
1
  module DiscoApp
2
- VERSION = "0.6.1"
2
+ VERSION = "0.6.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: disco_app
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gavin Ballard
@@ -244,19 +244,28 @@ files:
244
244
  - Rakefile
245
245
  - app/assets/images/disco_app/icon.svg
246
246
  - app/assets/javascripts/disco_app/disco_app.js
247
+ - app/assets/javascripts/disco_app/frame.js
248
+ - app/assets/javascripts/disco_app/shopify-turbolinks.js
247
249
  - app/assets/stylesheets/disco_app/bootstrap/_custom.scss
248
250
  - app/assets/stylesheets/disco_app/bootstrap/_variables.scss
249
251
  - app/assets/stylesheets/disco_app/disco/_buttons.scss
250
252
  - app/assets/stylesheets/disco_app/disco/_cards.scss
251
253
  - app/assets/stylesheets/disco_app/disco/_forms.scss
252
254
  - app/assets/stylesheets/disco_app/disco/_sections.scss
255
+ - app/assets/stylesheets/disco_app/disco/_tabs.scss
253
256
  - app/assets/stylesheets/disco_app/disco/_type.scss
254
257
  - app/assets/stylesheets/disco_app/disco/mixins/_flexbox.scss
255
258
  - app/assets/stylesheets/disco_app/disco_app.scss
259
+ - app/assets/stylesheets/disco_app/frame.scss
260
+ - app/assets/stylesheets/disco_app/frame/_buttons.scss
261
+ - app/assets/stylesheets/disco_app/frame/_forms.scss
262
+ - app/assets/stylesheets/disco_app/frame/_layout.scss
263
+ - app/assets/stylesheets/disco_app/frame/_type.scss
256
264
  - app/controllers/disco_app/app_proxy_controller.rb
257
265
  - app/controllers/disco_app/authenticated_controller.rb
258
266
  - app/controllers/disco_app/carrier_request_controller.rb
259
267
  - app/controllers/disco_app/charges_controller.rb
268
+ - app/controllers/disco_app/frame_controller.rb
260
269
  - app/controllers/disco_app/install_controller.rb
261
270
  - app/controllers/disco_app/webhooks_controller.rb
262
271
  - app/helpers/disco_app/application_helper.rb
@@ -280,6 +289,7 @@ files:
280
289
  - app/views/disco_app/charges/activate.html.erb
281
290
  - app/views/disco_app/charges/create.html.erb
282
291
  - app/views/disco_app/charges/new.html.erb
292
+ - app/views/disco_app/frame/frame.html.erb
283
293
  - app/views/disco_app/install/installing.html.erb
284
294
  - app/views/disco_app/install/uninstalling.html.erb
285
295
  - app/views/disco_app/proxy_errors/404.html.erb