designer 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +2 -0
  3. data/.gitignore +4 -0
  4. data/.travis.yml +17 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +142 -0
  7. data/LICENSE +21 -0
  8. data/README.md +102 -0
  9. data/Rakefile +27 -0
  10. data/TODO.md +6 -0
  11. data/app/assets/stylesheets/designer.scss +189 -0
  12. data/app/assets/stylesheets/designer/_texy.scss +311 -0
  13. data/app/controllers/designer/application_controller.rb +33 -0
  14. data/app/controllers/designer/editor_controller.rb +50 -0
  15. data/app/controllers/designer/images_controller.rb +66 -0
  16. data/app/helpers/designer/designer_helper.rb +95 -0
  17. data/app/javascript/designer/DefaultInput.vue +82 -0
  18. data/app/javascript/designer/components/DefaultForm.vue +65 -0
  19. data/app/javascript/designer/components/DefaultInput.vue +82 -0
  20. data/app/javascript/designer/components/MediaGallery.vue +564 -0
  21. data/app/javascript/designer/components/SortableInputArray.vue +74 -0
  22. data/app/javascript/designer/editor.js +65 -0
  23. data/app/javascript/designer/helpers.js +73 -0
  24. data/app/javascript/designer/index.js +136 -0
  25. data/app/javascript/packs/designer.js +2 -0
  26. data/app/views/designer/application/notifications.js.erb +13 -0
  27. data/app/views/designer/editor/show.html.slim +88 -0
  28. data/app/views/designer/elements/_image.html.slim +11 -0
  29. data/app/views/designer/elements/_quote.html.slim +7 -0
  30. data/app/views/designer/elements/_separator.html.slim +1 -0
  31. data/app/views/designer/elements/_text.html.slim +5 -0
  32. data/app/views/layouts/designer/application.html.slim +9 -0
  33. data/bin/test +6 -0
  34. data/bin/webpack +19 -0
  35. data/bin/webpack-dev-server +19 -0
  36. data/config/routes.rb +6 -0
  37. data/designer.gemspec +29 -0
  38. data/lib/designer.rb +10 -0
  39. data/lib/designer/attribute.rb +15 -0
  40. data/lib/designer/configuration.rb +6 -0
  41. data/lib/designer/engine.rb +35 -0
  42. data/lib/designer/version.rb +5 -0
  43. data/lib/tasks/designer.rake +20 -0
  44. data/lib/templates/dev_installer.rb +13 -0
  45. data/lib/templates/installer.rb +11 -0
  46. data/package.json +33 -0
  47. data/yarn.lock +288 -0
  48. metadata +160 -0
@@ -0,0 +1,311 @@
1
+ //
2
+ // Texy.scss
3
+ // Semantic markup for web publishing.
4
+ //
5
+ // Copyright 2018 Kam Low
6
+ // https://sourcey.com
7
+ //
8
+
9
+ @mixin texy(
10
+ $font-sans-serif: sans-serif,
11
+ $font-serif: serif,
12
+ $font-size: 18px,
13
+ $font-weight: 400,
14
+ $line-height: 32px,
15
+
16
+ $heading-weight: 600,
17
+ $heading-color: #111,
18
+
19
+ $caption-font-size: 14px,
20
+ $caption-font-weight: 400,
21
+ $caption-line-height: 1.5,
22
+ $caption-text-color: #454545,
23
+
24
+ $text-color: #333,
25
+ $link-color: #007bff,
26
+ $accent-color: #6610f2,
27
+ $separator-color: #eee,
28
+
29
+ $paragraph-margin: 1.75rem,
30
+ $block-margin: 3rem,
31
+ $pull-margin: 5rem) {
32
+
33
+ font-size: $font-size;
34
+ font-weight: $font-weight;
35
+
36
+
37
+ //
38
+ /// Headings
39
+
40
+ h1, h2, h3, h4, h5, h6 {
41
+ margin-bottom: $paragraph-margin;
42
+ font-weight: $heading-weight;
43
+ color: $heading-color;
44
+
45
+ + .block {
46
+ margin-top: 0;
47
+ }
48
+ }
49
+ h1 {
50
+ margin-top: $block-margin;
51
+ font-size: $font-size * 2;
52
+ }
53
+ h2 {
54
+ margin-top: $block-margin;
55
+ font-size: $font-size * 1.75;
56
+ }
57
+ h3 {
58
+ font-size: $font-size * 1.5;
59
+ }
60
+ h4 {
61
+ font-size: $font-size * 1.33;
62
+ }
63
+ h5 {
64
+ font-size: $font-size * 1.25;
65
+ }
66
+
67
+
68
+ //
69
+ /// Typography
70
+
71
+ p, ul, ol, > pre, > img, > center {
72
+ margin-bottom: $paragraph-margin;
73
+ }
74
+
75
+ p, li, cite, figcaption {
76
+ a {
77
+ color: inherit;
78
+ position: relative;
79
+
80
+ &:before {
81
+ content: '';
82
+ position: absolute;
83
+ left: 0;
84
+ right: 0;
85
+ bottom: -.25rem;
86
+ z-index: -1;
87
+ border-bottom: 2px solid lighten($link-color, 30%);
88
+ }
89
+
90
+ &:hover {
91
+ text-decoration: none;
92
+ color: black;
93
+
94
+ &:before {
95
+ border-color: $link-color;
96
+ }
97
+ }
98
+ }
99
+ }
100
+
101
+ img {
102
+ max-width: 100%;
103
+
104
+ &.block {
105
+ display: block;
106
+ }
107
+ &.left {
108
+ float: left;
109
+ margin-right: $paragraph-margin;
110
+ margin-bottom: $paragraph-margin;
111
+ }
112
+ &.right {
113
+ float: left;
114
+ margin-left: $paragraph-margin;
115
+ margin-bottom: $paragraph-margin;
116
+ }
117
+ }
118
+
119
+ hr {
120
+ border-top: 1px solid $separator-color;
121
+ margin-top: $block-margin;
122
+ margin-bottom: $block-margin;
123
+ clear: both;
124
+ }
125
+
126
+
127
+ //
128
+ /// Helpers
129
+
130
+ .block {
131
+ margin-top: $block-margin;
132
+ margin-bottom: $block-margin;
133
+ }
134
+
135
+ .center {
136
+ text-align: center;
137
+ margin-left: auto;
138
+ margin-right: auto;
139
+ }
140
+
141
+ .pull {
142
+ @include media-breakpoint-up(lg) {
143
+ margin-left: -$pull-margin;
144
+ margin-right: -$pull-margin;
145
+ }
146
+ }
147
+
148
+ .left {
149
+ float: left;
150
+ max-width: 40%;
151
+ margin-top: $block-margin * .75;
152
+ margin-bottom: $block-margin * .75;
153
+ margin-right: $block-margin;
154
+
155
+ // &.out,
156
+ // &.pull {
157
+ // margin-left: -$pull-margin;
158
+ // }
159
+ }
160
+
161
+ .right {
162
+ float: right;
163
+ max-width: 40%;
164
+ margin-top: $block-margin * .75;
165
+ margin-bottom: $block-margin * .75;
166
+ margin-left: $block-margin;
167
+
168
+ // &.out,
169
+ // &.pull {
170
+ // margin-right: -$pull-margin;
171
+ // }
172
+ }
173
+
174
+
175
+ //
176
+ /// Blockquotes
177
+
178
+ blockquote {
179
+ color: $gray-900;
180
+
181
+ img {
182
+ margin-bottom: $paragraph-margin;
183
+ }
184
+
185
+ p:only-of-type {
186
+ margin-bottom: 0;
187
+ }
188
+
189
+ cite {
190
+ font-size: $caption-font-size;
191
+ font-weight: $caption-font-weight;
192
+ line-height: $caption-line-height;
193
+ color: $caption-text-color;
194
+
195
+ &:before {
196
+ // Add a dash and space before citations
197
+ // &mdhash;  in Hexadecimal
198
+ content:'\2014\00a0';
199
+ }
200
+ }
201
+
202
+ &.left,
203
+ &.right {
204
+ border-top: 6px solid $accent-color;
205
+ border-bottom: 1px solid $text-color;
206
+ padding-top: 1.5rem;
207
+ padding-bottom: 1rem;
208
+ font-weight: 500;
209
+ line-height: 1.725;
210
+
211
+ cite {
212
+ display: block;
213
+ margin-top: 0.75rem;
214
+ font-style: italic;
215
+ }
216
+ }
217
+
218
+ &.block {
219
+ font-family: $font-serif;
220
+ font-size: $font-size * 1.25;
221
+ font-weight: 400;
222
+ font-style: italic;
223
+
224
+ border-top: 3px solid $accent-color;
225
+ border-bottom: 1px solid $separator-color;
226
+ padding-top: $paragraph-margin;
227
+ // padding-bottom: $paragraph-margin;
228
+ // margin-top: $paragraph-margin;
229
+ // margin-bottom: $paragraph-margin;
230
+
231
+ cite {
232
+ font-family: $font-sans-serif;
233
+ margin-top: 1rem;
234
+ margin-bottom: 1.25rem;
235
+ display: block;
236
+ // font-style: normal;
237
+ }
238
+ }
239
+ }
240
+
241
+
242
+ //
243
+ /// Image Figure
244
+
245
+ figure {
246
+ margin-top: $block-margin;
247
+ margin-bottom: $block-margin;
248
+
249
+ p {
250
+ margin-bottom: 0;
251
+ }
252
+
253
+ figcaption {
254
+ font-size: $caption-font-size;
255
+ font-weight: $caption-font-weight;
256
+ line-height: $caption-line-height;
257
+ color: $caption-text-color;
258
+ padding: .5rem 0 0;
259
+ // padding: .5rem 0;
260
+ // border-bottom: 2px solid $text-color;
261
+ }
262
+
263
+ // &.block {
264
+ // // margin-top: 3rem;
265
+ //
266
+ // figcaption {
267
+ // // border-color: 2px solid $separator-color;
268
+ // }
269
+ // }
270
+ }
271
+
272
+
273
+ // Full Layout
274
+ // @include media-breakpoint-up(lg) {
275
+ // }
276
+
277
+ // Mobile Layout
278
+ @include media-breakpoint-down(lg) {
279
+ figure {
280
+ &.left {
281
+ margin-left: 0 !important;
282
+ margin-right: $paragraph-margin !important;
283
+ }
284
+
285
+ &.right {
286
+ margin-left: $paragraph-margin !important;
287
+ margin-right: 0 !important;
288
+ }
289
+ }
290
+
291
+ blockquote {
292
+ &.left,
293
+ &.right {
294
+ margin: 0;
295
+ float: none;
296
+ max-width: none;
297
+
298
+ &.out,
299
+ &.pull {
300
+ margin: $paragraph-margin 0;
301
+ border-top: 3px solid $accent-color;
302
+ border-bottom: 1px solid $text-color;
303
+ }
304
+ }
305
+ }
306
+ }
307
+
308
+ // Mobile Layout
309
+ @include media-breakpoint-down(xs) {
310
+ }
311
+ }
@@ -0,0 +1,33 @@
1
+ module Designer
2
+ class ApplicationController < ActionController::Base
3
+ before_action :set_host_for_local_storage
4
+
5
+ protected
6
+
7
+ def set_host_for_local_storage
8
+ ActiveStorage::Current.host = request.base_url if Rails.application.config.active_storage.service == :local
9
+ end
10
+
11
+ helper_method :resource_name, :resource_type
12
+
13
+ def resource_name
14
+ params[:resource_name]
15
+ end
16
+
17
+ def resource_type
18
+ params[:resource_name].classify
19
+ end
20
+
21
+ def set_resource
22
+ @resource = resource_type.constantize.find(params[:id])
23
+ end
24
+
25
+ def resource_params
26
+ params.require(:resource).permit!
27
+ end
28
+
29
+ def set_host_for_local_storage
30
+ ActiveStorage::Current.host = request.base_url if Rails.application.config.active_storage.service == :local
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,50 @@
1
+ require_dependency "designer/application_controller"
2
+
3
+ module Designer
4
+ class EditorController < ApplicationController
5
+ before_action :set_resource
6
+ # skip_before_action :verify_authenticity_token
7
+
8
+ def show
9
+ end
10
+
11
+ def update
12
+ if @resource.update(resource_params.merge(elements: resource_elements))
13
+ render_success
14
+ else
15
+ render_error
16
+ end
17
+ end
18
+
19
+ # def preview
20
+ # raise 'virtual'
21
+ # end
22
+
23
+ protected
24
+
25
+ def resource_elements
26
+ # BUG: The front end stringifies the elements JSON, but this is getting
27
+ # auto-parsed by Rails only in production, so check if it's a string first.
28
+ @resource_elements ||= params[:resource][:elements]&.is_a?(String) ?
29
+ JSON.parse(params[:resource][:elements]) : params[:resource][:elements]
30
+ end
31
+
32
+ def render_success message = nil
33
+ if request.xhr?
34
+ flash.now[:notice] = message || "#{resource_type.classify} saved"
35
+ render :notifications
36
+ else
37
+ render json: @resource
38
+ end
39
+ end
40
+
41
+ def render_error
42
+ if request.xhr?
43
+ flash.now[:error] = @resource.errors.full_messages.join('. ')
44
+ render :notifications, status: :unprocessable_entity
45
+ else
46
+ head :unprocessable_entity
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,66 @@
1
+ require_dependency "designer/application_controller"
2
+
3
+ module Designer
4
+ class ImagesController < ApplicationController
5
+ before_action :set_resource
6
+ before_action :set_attachment, only: [:destroy]
7
+ # skip_before_action :verify_authenticity_token
8
+
9
+ def index
10
+ render json: designer_images_json
11
+ end
12
+
13
+ def create
14
+ @resource.attachments.attach(params[:file])
15
+
16
+ render json: designer_images_json
17
+ end
18
+
19
+ def destroy
20
+ @attachment.purge_later
21
+ end
22
+
23
+ private
24
+
25
+ def set_attachment
26
+ @attachment = ActiveStorage::Attachment.where(record: @resource).joins(:blob)
27
+ .where(active_storage_blobs: {key: params[:key]}).first
28
+ end
29
+
30
+ def all_attachments
31
+ @attachments ||= ActiveStorage::Attachment.where(record: @resource).joins(:blob)
32
+ end
33
+
34
+ def designer_images_json
35
+ all_attachments.map do |attachment|
36
+ designer_image_json attachment
37
+ end
38
+ end
39
+
40
+ def designer_image_json attachment
41
+ {
42
+ key: attachment.key,
43
+ # signed_id: attachment.signed_id,
44
+ name: attachment.filename,
45
+ size: attachment.byte_size,
46
+ kind: attachment.name,
47
+ thumbnail_url: attachment.variant(resize: '100x100').processed.service_url,
48
+ delete_url: image_path(key: attachment.key, id: @resource.id, resource_name: params[:resource_name])
49
+ # sources: {
50
+ # 'Image Key' => attachment.key,
51
+ # 'Signed ID' => attachment.signed_id,
52
+ # 'Small: 256x' => Image::UrlResolver.new(attachment, {size: :small}).perform,
53
+ # 'Small Square: 256x256' => Image::UrlResolver.new(attachment, {size: :small_square}).perform,
54
+ # 'Thumb: 512x' => Image::UrlResolver.new(attachment, {size: :thumb}).perform,
55
+ # 'Thumb Square: 512x512' => Image::UrlResolver.new(attachment, {size: :thumb_square}).perform,
56
+ # 'Main: 1024x' => Image::UrlResolver.new(attachment, {size: :main}).perform,
57
+ # 'Cover: 1600x' => Image::UrlResolver.new(attachment, {size: :cover}).perform,
58
+ # 'Newsletter: 600x600' => Image::UrlResolver.new(attachment, {size: {width: 600, height: 600, crop: 'fill'}}).perform,
59
+ # 'Newsletter: 600x300' => Image::UrlResolver.new(attachment, {size: {width: 600, height: 300, crop: 'fill'}}).perform,
60
+ # 'Newsletter: 300x300' => Image::UrlResolver.new(attachment, {size: {width: 300, height: 300, crop: 'fill'}}).perform,
61
+ # 'Newsletter: 200x200' => Image::UrlResolver.new(attachment, {size: {width: 200, height: 200, crop: 'fill'}}).perform
62
+ # }
63
+ }
64
+ end
65
+ end
66
+ end