coveragebook_components 0.5.0 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/build/coco/app.css +28 -28
  3. data/app/assets/build/coco/app.js +8113 -974
  4. data/app/assets/build/coco/book.css +3 -0
  5. data/app/assets/build/coco/book.js +37 -4
  6. data/app/assets/js/base/polyfills/request-submit.js +39 -0
  7. data/app/assets/js/base/setup.js +2 -0
  8. data/app/assets/js/helpers/path.js +9 -1
  9. data/app/assets/js/helpers/screenshot.js +20 -4
  10. data/app/components/coco/app/blocks/slide_editor/slide_editor.css +8 -11
  11. data/app/components/coco/app/blocks/slide_editor/slide_editor.html.erb +155 -196
  12. data/app/components/coco/app/blocks/slide_editor/slide_editor.js +92 -70
  13. data/app/components/coco/app/blocks/slide_editor/slide_editor.rb +36 -85
  14. data/app/components/coco/app/elements/alert/alert.css +1 -1
  15. data/app/components/coco/app/elements/button/button.css +11 -11
  16. data/app/components/coco/app/elements/color_picker_button/color_picker_button.html.erb +17 -16
  17. data/app/components/coco/app/elements/color_picker_button/color_picker_button.js +0 -8
  18. data/app/components/coco/app/elements/color_picker_button/color_picker_button.rb +2 -15
  19. data/app/components/coco/app/elements/image_picker/image_picker.html.erb +4 -4
  20. data/app/components/coco/app/elements/image_picker/image_picker.js +18 -6
  21. data/app/components/coco/app/elements/image_picker/image_picker.rb +2 -11
  22. data/app/components/coco/app/elements/image_picker_button/image_picker_button.html.erb +9 -8
  23. data/app/components/coco/app/elements/image_picker_button/image_picker_button.js +10 -23
  24. data/app/components/coco/app/elements/image_picker_button/image_picker_button.rb +19 -35
  25. data/app/components/coco/app/elements/seamless_textarea/seamless_textarea.html.erb +7 -4
  26. data/app/components/coco/app/elements/seamless_textarea/seamless_textarea.js +9 -3
  27. data/app/components/coco/app/elements/seamless_textarea/seamless_textarea.rb +5 -20
  28. data/app/components/coco/base/button/button.css +3 -3
  29. data/app/components/coco/base/button/button.js +1 -3
  30. data/app/components/coco/base/image_uploader/image_uploader.html.erb +3 -2
  31. data/app/components/coco/base/image_uploader/image_uploader.rb +2 -12
  32. data/app/components/coco/book/blocks/slides/media_slide/media_slide.css +1 -1
  33. data/app/components/coco/component.rb +1 -0
  34. data/app/components/coco/concerns/has_name.rb +1 -1
  35. data/app/components/coco/concerns/translatable.rb +18 -0
  36. data/config/credentials/production.key +1 -0
  37. data/config/credentials/production.yml.enc +1 -0
  38. data/config/icons.json +886 -0
  39. data/config/locales/coco.en.yml +22 -0
  40. data/config/tailwind.app.config.cjs +21 -0
  41. data/config/tailwind.base.config.cjs +79 -0
  42. data/config/tailwind.book.config.cjs +20 -0
  43. data/config/tokens.cjs +229 -0
  44. data/config/utils.cjs +16 -0
  45. data/lib/coco.rb +1 -1
  46. metadata +13 -6
  47. data/app/assets/build/coco/app.dev.css +0 -3427
  48. data/app/assets/build/coco/app.dev.js +0 -24891
  49. data/app/assets/build/coco/book.dev.css +0 -992
  50. data/app/assets/build/coco/book.dev.js +0 -19840
@@ -893,8 +893,11 @@ select {
893
893
  font-size: var(--text-font-size);
894
894
  }
895
895
  [data-coco][data-component="book-media-slide"] img {
896
+ height: 100%;
896
897
  width: 100%;
897
898
  border-radius: 0.375rem;
899
+ -o-object-fit: contain;
900
+ object-fit: contain;
898
901
  }
899
902
  .static {
900
903
  position: static;
@@ -11636,6 +11636,40 @@ ${t4.join("\n")}`);
11636
11636
  // ../../../node_modules/@hotwired/turbo-rails/app/javascript/turbo/index.js
11637
11637
  addEventListener("turbo:before-fetch-request", encodeMethodIntoRequestBody);
11638
11638
 
11639
+ // base/polyfills/request-submit.js
11640
+ (function(prototype) {
11641
+ if (typeof prototype.requestSubmit == "function")
11642
+ return;
11643
+ prototype.requestSubmit = function(submitter) {
11644
+ if (submitter) {
11645
+ validateSubmitter(submitter, this);
11646
+ submitter.click();
11647
+ } else {
11648
+ submitter = document.createElement("input");
11649
+ submitter.type = "submit";
11650
+ submitter.hidden = true;
11651
+ this.appendChild(submitter);
11652
+ submitter.click();
11653
+ this.removeChild(submitter);
11654
+ }
11655
+ };
11656
+ function validateSubmitter(submitter, form) {
11657
+ submitter instanceof HTMLElement || raise(TypeError, "parameter 1 is not of type 'HTMLElement'");
11658
+ submitter.type == "submit" || raise(TypeError, "The specified element is not a submit button");
11659
+ submitter.form == form || raise(
11660
+ DOMException,
11661
+ "The specified element is not owned by this form element",
11662
+ "NotFoundError"
11663
+ );
11664
+ }
11665
+ function raise(errorConstructor, message, name) {
11666
+ throw new errorConstructor(
11667
+ "Failed to execute 'requestSubmit' on 'HTMLFormElement': " + message + ".",
11668
+ name
11669
+ );
11670
+ }
11671
+ })(HTMLFormElement.prototype);
11672
+
11639
11673
  // ../../../node_modules/alpinejs/dist/module.esm.js
11640
11674
  var flushPending = false;
11641
11675
  var flushing = false;
@@ -19579,10 +19613,8 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
19579
19613
  this.collapsed = false;
19580
19614
  return;
19581
19615
  }
19582
- this.setTooltipText();
19583
19616
  this.$root.setAttribute("data-collapsed", collapsed ? "true" : "false");
19584
19617
  });
19585
- this.$watch("$options.state", () => this.setTooltipText());
19586
19618
  },
19587
19619
  setTooltipText() {
19588
19620
  if (this.disabled) {
@@ -19685,6 +19717,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
19685
19717
  root: {
19686
19718
  "x-options": "options",
19687
19719
  "x-tooltip": "tooltipText",
19720
+ "x-effect": "setTooltipText",
19688
19721
  "@confirmation:confirm": "approveAndRun",
19689
19722
  "@confirmation:cancel": "cancelConfirmation",
19690
19723
  "@dropdown:show": "setState('active')",
@@ -19802,14 +19835,14 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
19802
19835
  };
19803
19836
  });
19804
19837
 
19805
- // import-glob:/home/runner/work/coco/coco/app/assets/js/base|@baseComponents/**/*.js
19838
+ // import-glob:/Users/mark/Projects/coveragebook/coco/app/assets/js/base|@baseComponents/**/*.js
19806
19839
  var modules = [button_exports, dropdown_exports, icon_exports, image_uploader_exports];
19807
19840
  var __default = modules;
19808
19841
 
19809
19842
  // base/components.js
19810
19843
  var components_default = registerComponents(__default);
19811
19844
 
19812
- // import-glob:/home/runner/work/coco/coco/app/assets/js/book|@bookComponents/**/*.js
19845
+ // import-glob:/Users/mark/Projects/coveragebook/coco/app/assets/js/book|@bookComponents/**/*.js
19813
19846
  var modules2 = [];
19814
19847
  var __default2 = modules2;
19815
19848
 
@@ -0,0 +1,39 @@
1
+ (function (prototype) {
2
+ if (typeof prototype.requestSubmit == "function") return;
3
+
4
+ prototype.requestSubmit = function (submitter) {
5
+ if (submitter) {
6
+ validateSubmitter(submitter, this);
7
+ submitter.click();
8
+ } else {
9
+ submitter = document.createElement("input");
10
+ submitter.type = "submit";
11
+ submitter.hidden = true;
12
+ this.appendChild(submitter);
13
+ submitter.click();
14
+ this.removeChild(submitter);
15
+ }
16
+ };
17
+
18
+ function validateSubmitter(submitter, form) {
19
+ submitter instanceof HTMLElement ||
20
+ raise(TypeError, "parameter 1 is not of type 'HTMLElement'");
21
+ submitter.type == "submit" ||
22
+ raise(TypeError, "The specified element is not a submit button");
23
+ submitter.form == form ||
24
+ raise(
25
+ DOMException,
26
+ "The specified element is not owned by this form element",
27
+ "NotFoundError"
28
+ );
29
+ }
30
+
31
+ function raise(errorConstructor, message, name) {
32
+ throw new errorConstructor(
33
+ "Failed to execute 'requestSubmit' on 'HTMLFormElement': " +
34
+ message +
35
+ ".",
36
+ name
37
+ );
38
+ }
39
+ })(HTMLFormElement.prototype);
@@ -2,6 +2,8 @@ import "container-query-polyfill";
2
2
  import "alpine-turbo-drive-adapter";
3
3
  import * as Turbo from "@hotwired/turbo-rails";
4
4
 
5
+ import "./polyfills/request-submit";
6
+
5
7
  import Alpine from "@libs/alpine";
6
8
 
7
9
  document.addEventListener("DOMContentLoaded", () => {
@@ -2,4 +2,12 @@ function stripExtension(filename) {
2
2
  return filename.substring(0, filename.lastIndexOf(".")) || filename;
3
3
  }
4
4
 
5
- export { stripExtension };
5
+ function dirname(path) {
6
+ return path ? path.match(/.*\//) : path;
7
+ }
8
+
9
+ function basename(path) {
10
+ return path ? path.replace(/.*\//, "") : path;
11
+ }
12
+
13
+ export { stripExtension, dirname, basename };
@@ -1,8 +1,13 @@
1
- import { toBlob } from "html-to-image";
1
+ import html2canvas from "html2canvas";
2
2
  import { stripExtension } from "./path";
3
3
  import { isObject } from "./lang";
4
4
  import { blobToFile } from "./file";
5
5
 
6
+ const screenshotDefaultOptions = {
7
+ useCORS: true,
8
+ logging: false,
9
+ };
10
+
6
11
  function generateScreenshotFilename(name = null, ext = null) {
7
12
  name = [stripExtension(name || "screenshot"), new Date().getTime()].join("-");
8
13
  return ext ? `${name}.${ext}` : name;
@@ -16,11 +21,22 @@ async function captureElementScreenshot(el, filename, opts = {}) {
16
21
  opts = filename;
17
22
  }
18
23
 
19
- filename = generateScreenshotFilename(filename, "jpg");
24
+ const screenshotFilename = generateScreenshotFilename(filename, "jpg");
25
+ const screenshotOptions = {
26
+ ...screenshotDefaultOptions,
27
+ ...opts,
28
+ };
20
29
 
21
- const imageBlob = await toBlob(el, opts);
30
+ const canvas = await html2canvas(el, screenshotOptions);
31
+ const imageBlob = await new Promise((resolve, reject) => {
32
+ canvas.toBlob((result) => {
33
+ return result
34
+ ? resolve(result)
35
+ : reject(new Error("Screenshot could not be created"));
36
+ });
37
+ });
22
38
 
23
- return blobToFile(imageBlob, filename, "image/jpg");
39
+ return blobToFile(imageBlob, screenshotFilename, "image/jpg");
24
40
  }
25
41
 
26
42
  export { captureElementScreenshot };
@@ -8,8 +8,12 @@
8
8
  @apply mb-4 xl:mb-6;
9
9
  }
10
10
 
11
+ .editor-form form {
12
+ @apply hidden;
13
+ }
14
+
11
15
  .editor-slide {
12
- @apply shadow-lg;
16
+ @apply shadow-md;
13
17
 
14
18
  textarea {
15
19
  @apply flex-none w-full;
@@ -20,16 +24,12 @@
20
24
  @apply cursor-not-allowed;
21
25
  }
22
26
 
23
- .editor-thumbnail-file {
24
- @apply hidden pointer-events-none;
25
- }
26
-
27
- .editor-screenshot-wrapper {
27
+ .editor-thumbnail-wrapper {
28
28
  @apply w-0 overflow-hidden relative;
29
29
  }
30
30
 
31
- .editor-screenshot {
32
- @apply absolute w-[800px] top-0 z-[-1000] pointer-events-none;
31
+ .editor-thumbnail {
32
+ @apply absolute w-[500px] top-0 z-[-1000] pointer-events-none;
33
33
  }
34
34
 
35
35
  .editor-icon-bg-color {
@@ -37,9 +37,6 @@
37
37
  stroke-width: 2px;
38
38
  }
39
39
 
40
- .editor-icon-text-color {
41
- }
42
-
43
40
  [data-component="app-seamless-textarea"] {
44
41
  textarea {
45
42
  @apply outline outline-1 outline-transparent outline-offset-0;
@@ -1,222 +1,169 @@
1
1
  <%= render component_tag(x: {
2
2
  data: x_data("appSlideEditor", alpine_props),
3
- ":class": "{ready}",
4
- "@direct-upload:error": "directUploadError",
3
+ ":class": "{ready}"
5
4
  }) do %>
6
- <%= form_with(**form_args(
7
- class: "editor-form",
8
- "x-ref": "form",
9
- "@turbo:submit-end": "submitEnd",
10
- "@turbo:fetch-request-error": "submitError",
11
- "@direct-uploads:end": "save"
12
- )) do |f| %>
13
- <%= f.hidden_field(layout_name, **layout_options, "x-model": "layout") if layout? %>
14
- <%= f.file_field(thumbnail_name, accept: "image/*", class: "editor-thumbnail-file", "x-ref": "thumbnail") if thumbnail? %>
15
-
16
- <div class="editor-toolbar">
17
- <%= coco_toolbar do |toolbar| %>
18
- <% toolbar.with_section do |section| %>
19
- <% if bg_color? %>
20
- <% section.with_color_picker_button(
21
- input_name: bg_color_name,
22
- selected: bg_color_value,
23
- form_builder: f,
24
- wrapper: {
25
- data: {
26
- role: "bg-color-picker"
27
- },
28
- x: {
29
- modelable: "selectedColor",
30
- model: "bgColor"
31
- }
5
+ <div class="editor-toolbar">
6
+ <%= coco_toolbar do |toolbar| %>
7
+ <% toolbar.with_section do |section| %>
8
+ <% if bg_color? %>
9
+ <% section.with_color_picker_button(
10
+ **@bg_color_options.to_h,
11
+ wrapper: {
12
+ data: {
13
+ role: "bg-color-picker"
14
+ },
15
+ x: {
16
+ "@color-picker:change": "bgColor = $event.detail.color"
32
17
  }
33
- ) do |button| %>
34
- <% button.with_picker %>
35
- <% button.with_text { "Background color" } %>
36
- <% button.with_icon do %>
37
- <svg viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="editor-icon-bg-color">
38
- <path d="M12 22a7 7 0 0 0 7-7c0-2-1-3.9-3-5.5s-3.5-4-4-6.5c-.5 2.5-2 4.9-4 6.5C6 11.1 5 13 5 15a7 7 0 0 0 7 7z"></path>
39
- </svg>
40
- <% end %>
18
+ }
19
+ ) do |button| %>
20
+ <% button.with_picker %>
21
+ <% button.with_text { tt("bg_color_picker.label") } %>
22
+ <% button.with_icon do %>
23
+ <svg viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="editor-icon-bg-color">
24
+ <path d="M12 22a7 7 0 0 0 7-7c0-2-1-3.9-3-5.5s-3.5-4-4-6.5c-.5 2.5-2 4.9-4 6.5C6 11.1 5 13 5 15a7 7 0 0 0 7 7z"></path>
25
+ </svg>
41
26
  <% end %>
42
27
  <% end %>
43
-
44
- <% if bg_image? %>
45
- <% section.with_image_picker_button(
46
- icon: :image_plus,
47
- input_name: bg_image_name,
48
- src: bg_image_value,
49
- direct_upload: bg_image_options[:direct_upload],
50
- form_builder: f,
51
- wrapper: {
52
- data: {
53
- role: "bg-image-picker"
54
- },
55
- x: {
56
- modelable: "selectedImage",
57
- model: "bgImage"
58
- }
59
- }
60
- ) do |button| %>
61
- <% button.with_picker do |picker| %>
62
- <% picker.with_blank_state_text do %>
63
- Drag a jpg, png or gif onto the slide area...or...
64
- <% end %>
65
- <% end %>
28
+ <% end %>
66
29
 
67
- Background image
30
+ <% if bg_image? %>
31
+ <% section.with_image_picker_button(
32
+ icon: :image_plus,
33
+ src: bg_image_src,
34
+ wrapper: {
35
+ data: {
36
+ role: "bg-image-picker"
37
+ },
38
+ x: {
39
+ "@image-picker:change": "bgImage = $event.detail.image"
40
+ }
41
+ }
42
+ ) do |button| %>
43
+ <% button.with_picker do |picker| %>
44
+ <% picker.with_blank_state_text { tt("bg_image_picker.blank_state") } %>
68
45
  <% end %>
46
+
47
+ <%= tt("bg_image_picker.label") %>
69
48
  <% end %>
49
+ <% end %>
70
50
 
71
- <% if text_color? %>
72
- <% section.with_color_picker_button(
73
- input_name: text_color_name,
74
- selected: text_color_value,
75
- form_builder: f,
76
- wrapper: {
77
- data: {
78
- role: "text-color-picker"
79
- },
80
- x: {
81
- modelable: "selectedColor",
82
- model: "textColor"
83
- }
51
+ <% if text_color? %>
52
+ <% section.with_color_picker_button(
53
+ **@text_color_options.to_h,
54
+ wrapper: {
55
+ data: {
56
+ role: "text-color-picker"
57
+ },
58
+ x: {
59
+ "@color-picker:change": "textColor = $event.detail.color"
84
60
  }
85
- ) do |button| %>
86
- <% button.with_picker %>
87
- <% button.with_text { "Text color" } %>
88
- <% button.with_icon do %>
89
- <svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" class="editor-icon-text-color">
90
- <path d="M4.99994 13.3333L9.99994 3.33334L14.9999 13.3333" stroke="#111827" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
91
- <path d="M6.66656 10H13.3332" stroke="#111827" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
92
- <rect x="2.25" y="15.25" width="15.5" height="2.5" rx="1.25" fill="currentColor" stroke="#111827" stroke-width="0.5"/>
93
- </svg>
94
- <% end %>
61
+ }
62
+ ) do |button| %>
63
+ <% button.with_picker %>
64
+ <% button.with_text { tt("text_color_picker.label") } %>
65
+ <% button.with_icon do %>
66
+ <svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
67
+ <path d="M4.99994 13.3333L9.99994 3.33334L14.9999 13.3333" stroke="#111827" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
68
+ <path d="M6.66656 10H13.3332" stroke="#111827" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
69
+ <rect x="2.25" y="15.25" width="15.5" height="2.5" rx="1.25" fill="currentColor" stroke="#111827" stroke-width="0.5"/>
70
+ </svg>
95
71
  <% end %>
96
72
  <% end %>
97
73
  <% end %>
74
+ <% end %>
98
75
 
99
- <% toolbar.with_section do |section| %>
100
- <% section.with_button(
101
- icon: :undo_2,
102
- click: "history.undo",
103
- tooltip: "Undo",
104
- theme: :text_secondary,
105
- disabled: true,
106
- x: { "effect": "disabled = !history.undoable" },
107
- data: {
108
- role: "undo"
109
- }
110
- ) %>
76
+ <% toolbar.with_section do |section| %>
77
+ <% section.with_button(
78
+ icon: :undo_2,
79
+ click: "history.undo",
80
+ tooltip: tt("undo_button.tooltip"),
81
+ theme: :text_secondary,
82
+ disabled: true,
83
+ x: { "effect": "disabled = saving || !history.undoable" },
84
+ data: {
85
+ role: "undo"
86
+ }
87
+ ) %>
111
88
 
112
- <% section.with_button(
113
- icon: :redo_2,
114
- click: "history.redo",
115
- tooltip: "Redo",
116
- theme: :text_secondary,
117
- disabled: true,
118
- x: { "effect": "disabled = !history.redoable" },
119
- data: {
120
- role: "redo"
121
- }
122
- ) %>
123
-
124
- <% section.with_button(
125
- theme: :positive,
126
- icon: :check,
127
- collapsible: false,
128
- type: "submit",
129
- disabled: true,
130
- data: {
131
- role: "save"
132
- },
133
- x: {
134
- "@click.stop.prevent": "if(!loading) save()",
135
- "effect": "loading = saving; disabled = !history.undoable",
136
- ":class": "{'editor-saving': saving}"
137
- }
138
- ) do |button| %>
139
- <% button.with_state(:loading, text: "Saving...") %>
140
- Save
141
- <% end %>
89
+ <% section.with_button(
90
+ icon: :redo_2,
91
+ click: "history.redo",
92
+ tooltip: tt("redo_button.tooltip"),
93
+ theme: :text_secondary,
94
+ disabled: true,
95
+ x: { "effect": "disabled = saving || !history.redoable" },
96
+ data: {
97
+ role: "redo"
98
+ }
99
+ ) %>
100
+
101
+ <% section.with_button(
102
+ theme: :positive,
103
+ icon: :check,
104
+ collapsible: false,
105
+ type: "submit",
106
+ disabled: true,
107
+ data: {
108
+ role: "save"
109
+ },
110
+ x: {
111
+ "@click.stop.prevent": "if(!loading) save()",
112
+ "effect": "loading = saving; disabled = !history.undoable",
113
+ ":class": "{'editor-saving': saving}"
114
+ }
115
+ ) do |button| %>
116
+ <% button.with_state(:loading, text: tt("save_button.saving_label")) %>
117
+ <%= tt("save_button.label") %>
142
118
  <% end %>
143
- <% end %>
144
- </div>
145
-
146
- <%# Editable slide %>
147
- <div
148
- class="editor-slide"
149
- x-ref="slide"
150
- @dragenter.stop.prevent="dragging = true"
151
- @dragover.stop.prevent="dragging = true"
152
- @dragleave.stop.prevent="dragging = false"
153
- @drop.stop.prevent="handleImageDrop($event)">
154
- <%= coco_editable_slide(
155
- **slide_args,
156
- data: {
157
- role: "slide"
158
- },
159
- x: {
160
- ":style": "slideStyles",
161
- ":class": "slideClasses",
162
- }
163
- ) do |slide| %>
164
- <% if title? %>
165
- <% slide.with_title do %>
166
- <%= coco_seamless_textarea(
167
- name: title_name,
168
- multiline: false,
169
- form_builder: f,
170
- **title_options,
171
- wrapper: {
172
- data: {
173
- role: "title-editor"
174
- },
175
- x: {
176
- modelable: "value",
177
- model: "title"
178
- }
179
- }
180
- ) %>
181
- <% end %>
119
+ <% end %>
120
+ <% end %>
121
+ </div>
122
+
123
+ <%# Editable slide %>
124
+ <div
125
+ class="editor-slide"
126
+ x-ref="slide"
127
+ @dragenter.stop.prevent="dragging = true"
128
+ @dragover.stop.prevent="dragging = true"
129
+ @dragleave.stop.prevent="dragging = false"
130
+ @drop.stop.prevent="handleImageDrop($event)">
131
+ <%= coco_editable_slide(
132
+ **slide_args,
133
+ data: {
134
+ role: "slide"
135
+ },
136
+ x: {
137
+ bind: "slide"
138
+ }
139
+ ) do |slide| %>
140
+ <% if title? %>
141
+ <% slide.with_title do %>
142
+ <%= title %>
182
143
  <% end %>
144
+ <% end %>
183
145
 
184
- <% if text_1? %>
185
- <% slide.with_text_1 do %>
186
- <%= coco_seamless_textarea(
187
- name: text_1_name,
188
- multiline: true,
189
- form_builder: f,
190
- **text_1_options,
191
- wrapper: {
192
- data: {
193
- role: "text-1-editor"
194
- },
195
- x: {
196
- modelable: "value",
197
- model: "text1"
198
- }
199
- }
200
- ) %>
201
- <% end %>
146
+ <% if text_1? %>
147
+ <% slide.with_text_1 do %>
148
+ <%= text_1 %>
202
149
  <% end %>
203
150
  <% end %>
204
- </div>
205
-
206
- <% if content %>
207
- <%# Any additional fields required %>
208
- <div class="editor-additional-content">
209
- <%= content %>
210
- </div>
211
151
  <% end %>
212
-
213
- <% end %>
214
-
215
- <% if thumbnail? %>
152
+ </div>
153
+
154
+ <% if generate_thumbnail? %>
216
155
  <%# Slide used for thumbnail generation %>
217
- <div class="editor-screenshot-wrapper">
218
- <div x-ref="screenshot" class="editor-screenshot">
219
- <%= coco_editable_slide(**slide_args) do |slide| %>
156
+ <div class="editor-thumbnail-wrapper">
157
+ <div x-ref="thumbnail" class="editor-thumbnail">
158
+ <%= coco_editable_slide(
159
+ **slide_args,
160
+ data: {
161
+ role: "slide-thumbnail"
162
+ },
163
+ x: {
164
+ bind: "slide"
165
+ }
166
+ ) do |slide| %>
220
167
  <% if title? %>
221
168
  <% slide.with_title do %>
222
169
  <span x-text="title"></span>
@@ -232,4 +179,16 @@
232
179
  </div>
233
180
  </div>
234
181
  <% end %>
182
+
183
+ <% if content %>
184
+ <div
185
+ class="editor-form"
186
+ x-ref="form"
187
+ @turbo:submit-end="submitSuccess"
188
+ @turbo:fetch-request-error="submitError"
189
+ @direct-upload:error="directUploadError"
190
+ @direct-uploads:end="save">
191
+ <%= content %>
192
+ </div>
193
+ <% end %>
235
194
  <% end %>