coveragebook_components 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/build/coco/app.css +21 -23
- data/app/assets/build/coco/app.js +7980 -888
- data/app/assets/build/coco/book.js +35 -2
- data/app/assets/js/base/polyfills/request-submit.js +39 -0
- data/app/assets/js/base/setup.js +2 -0
- data/app/assets/js/helpers/screenshot.js +20 -4
- data/app/components/coco/app/blocks/slide_editor/slide_editor.css +4 -11
- data/app/components/coco/app/blocks/slide_editor/slide_editor.html.erb +33 -29
- data/app/components/coco/app/blocks/slide_editor/slide_editor.js +50 -81
- data/app/components/coco/app/blocks/slide_editor/slide_editor.rb +5 -5
- data/app/components/coco/app/elements/button/button.css +11 -11
- data/app/components/coco/base/button/button.css +3 -3
- data/app/components/coco/base/button/button.js +1 -3
- data/app/components/coco/component.rb +1 -0
- data/app/components/coco/concerns/has_name.rb +1 -1
- data/app/components/coco/concerns/translatable.rb +18 -0
- data/config/credentials/production.key +1 -0
- data/config/credentials/production.yml.enc +1 -0
- data/config/icons.json +886 -0
- data/config/locales/coco.en.yml +22 -0
- data/config/tailwind.app.config.cjs +21 -0
- data/config/tailwind.base.config.cjs +79 -0
- data/config/tailwind.book.config.cjs +20 -0
- data/config/tokens.cjs +229 -0
- data/config/utils.cjs +16 -0
- data/lib/coco.rb +1 -1
- metadata +13 -2
@@ -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')",
|
@@ -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);
|
data/app/assets/js/base/setup.js
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
-
import
|
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
|
-
|
24
|
+
const screenshotFilename = generateScreenshotFilename(filename, "jpg");
|
25
|
+
const screenshotOptions = {
|
26
|
+
...screenshotDefaultOptions,
|
27
|
+
...opts,
|
28
|
+
};
|
20
29
|
|
21
|
-
const
|
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,
|
39
|
+
return blobToFile(imageBlob, screenshotFilename, "image/jpg");
|
24
40
|
}
|
25
41
|
|
26
42
|
export { captureElementScreenshot };
|
@@ -13,7 +13,7 @@
|
|
13
13
|
}
|
14
14
|
|
15
15
|
.editor-slide {
|
16
|
-
@apply shadow-
|
16
|
+
@apply shadow-md;
|
17
17
|
|
18
18
|
textarea {
|
19
19
|
@apply flex-none w-full;
|
@@ -24,16 +24,12 @@
|
|
24
24
|
@apply cursor-not-allowed;
|
25
25
|
}
|
26
26
|
|
27
|
-
.editor-thumbnail-
|
28
|
-
@apply hidden pointer-events-none;
|
29
|
-
}
|
30
|
-
|
31
|
-
.editor-screenshot-wrapper {
|
27
|
+
.editor-thumbnail-wrapper {
|
32
28
|
@apply w-0 overflow-hidden relative;
|
33
29
|
}
|
34
30
|
|
35
|
-
.editor-
|
36
|
-
@apply absolute w-[
|
31
|
+
.editor-thumbnail {
|
32
|
+
@apply absolute w-[500px] top-0 z-[-1000] pointer-events-none;
|
37
33
|
}
|
38
34
|
|
39
35
|
.editor-icon-bg-color {
|
@@ -41,9 +37,6 @@
|
|
41
37
|
stroke-width: 2px;
|
42
38
|
}
|
43
39
|
|
44
|
-
.editor-icon-text-color {
|
45
|
-
}
|
46
|
-
|
47
40
|
[data-component="app-seamless-textarea"] {
|
48
41
|
textarea {
|
49
42
|
@apply outline outline-1 outline-transparent outline-offset-0;
|
@@ -18,7 +18,7 @@
|
|
18
18
|
}
|
19
19
|
) do |button| %>
|
20
20
|
<% button.with_picker %>
|
21
|
-
<% button.with_text { "
|
21
|
+
<% button.with_text { tt("bg_color_picker.label") } %>
|
22
22
|
<% button.with_icon do %>
|
23
23
|
<svg viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="editor-icon-bg-color">
|
24
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>
|
@@ -41,12 +41,10 @@
|
|
41
41
|
}
|
42
42
|
) do |button| %>
|
43
43
|
<% button.with_picker do |picker| %>
|
44
|
-
<% picker.with_blank_state_text
|
45
|
-
Drag a jpg, png or gif onto the slide area or…
|
46
|
-
<% end %>
|
44
|
+
<% picker.with_blank_state_text { tt("bg_image_picker.blank_state") } %>
|
47
45
|
<% end %>
|
48
46
|
|
49
|
-
|
47
|
+
<%= tt("bg_image_picker.label") %>
|
50
48
|
<% end %>
|
51
49
|
<% end %>
|
52
50
|
|
@@ -63,9 +61,9 @@
|
|
63
61
|
}
|
64
62
|
) do |button| %>
|
65
63
|
<% button.with_picker %>
|
66
|
-
<% button.with_text { "
|
64
|
+
<% button.with_text { tt("text_color_picker.label") } %>
|
67
65
|
<% button.with_icon do %>
|
68
|
-
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"
|
66
|
+
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
69
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"/>
|
70
68
|
<path d="M6.66656 10H13.3332" stroke="#111827" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
|
71
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"/>
|
@@ -79,7 +77,7 @@
|
|
79
77
|
<% section.with_button(
|
80
78
|
icon: :undo_2,
|
81
79
|
click: "history.undo",
|
82
|
-
tooltip: "
|
80
|
+
tooltip: tt("undo_button.tooltip"),
|
83
81
|
theme: :text_secondary,
|
84
82
|
disabled: true,
|
85
83
|
x: { "effect": "disabled = saving || !history.undoable" },
|
@@ -91,7 +89,7 @@
|
|
91
89
|
<% section.with_button(
|
92
90
|
icon: :redo_2,
|
93
91
|
click: "history.redo",
|
94
|
-
tooltip: "
|
92
|
+
tooltip: tt("redo_button.tooltip"),
|
95
93
|
theme: :text_secondary,
|
96
94
|
disabled: true,
|
97
95
|
x: { "effect": "disabled = saving || !history.redoable" },
|
@@ -115,8 +113,8 @@
|
|
115
113
|
":class": "{'editor-saving': saving}"
|
116
114
|
}
|
117
115
|
) do |button| %>
|
118
|
-
<% button.with_state(:loading, text: "
|
119
|
-
|
116
|
+
<% button.with_state(:loading, text: tt("save_button.saving_label")) %>
|
117
|
+
<%= tt("save_button.label") %>
|
120
118
|
<% end %>
|
121
119
|
<% end %>
|
122
120
|
<% end %>
|
@@ -136,8 +134,7 @@
|
|
136
134
|
role: "slide"
|
137
135
|
},
|
138
136
|
x: {
|
139
|
-
|
140
|
-
":class": "slideClasses",
|
137
|
+
bind: "slide"
|
141
138
|
}
|
142
139
|
) do |slide| %>
|
143
140
|
<% if title? %>
|
@@ -153,24 +150,20 @@
|
|
153
150
|
<% end %>
|
154
151
|
<% end %>
|
155
152
|
</div>
|
156
|
-
|
157
|
-
<% if content %>
|
158
|
-
<div
|
159
|
-
class="editor-form"
|
160
|
-
x-ref="form"
|
161
|
-
@turbo:submit-end="submitSuccess"
|
162
|
-
@turbo:fetch-request-error="submitError"
|
163
|
-
@direct-upload:error="directUploadError"
|
164
|
-
@direct-uploads:end="save">
|
165
|
-
<%= content %>
|
166
|
-
</div>
|
167
|
-
<% end %>
|
168
153
|
|
169
|
-
<% if
|
154
|
+
<% if generate_thumbnail? %>
|
170
155
|
<%# Slide used for thumbnail generation %>
|
171
|
-
<div class="editor-
|
172
|
-
<div x-ref="
|
173
|
-
<%= coco_editable_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| %>
|
174
167
|
<% if title? %>
|
175
168
|
<% slide.with_title do %>
|
176
169
|
<span x-text="title"></span>
|
@@ -187,4 +180,15 @@
|
|
187
180
|
</div>
|
188
181
|
<% end %>
|
189
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 %>
|
190
194
|
<% end %>
|
@@ -2,16 +2,8 @@ import { CocoComponent } from "@js/coco";
|
|
2
2
|
import { getData } from "@helpers/alpine";
|
3
3
|
import { captureElementScreenshot } from "@helpers/screenshot";
|
4
4
|
import { isDark } from "@helpers/color";
|
5
|
-
import { wasSuccessful } from "@helpers/turbo_events";
|
6
5
|
import { withUndo } from "@js/base/mixins";
|
7
6
|
|
8
|
-
const thumbnailOpts = {
|
9
|
-
canvasWidth: 800,
|
10
|
-
canvasHeight: 500,
|
11
|
-
quality: 0.7,
|
12
|
-
pixelRatio: 1,
|
13
|
-
};
|
14
|
-
|
15
7
|
export default CocoComponent("appSlideEditor", (data) => {
|
16
8
|
const initialData = {
|
17
9
|
layout: data.layout,
|
@@ -44,9 +36,6 @@ export default CocoComponent("appSlideEditor", (data) => {
|
|
44
36
|
},
|
45
37
|
|
46
38
|
init() {
|
47
|
-
// Update thumbnail field when new thumbnail is generated
|
48
|
-
this.$watch("thumbnailFile", () => this._syncThumbnailField());
|
49
|
-
|
50
39
|
this.$watch("errors", (errors) => {
|
51
40
|
errors.forEach((error) => console.error(error.message)); // TODO display errors properly!
|
52
41
|
});
|
@@ -82,10 +71,12 @@ export default CocoComponent("appSlideEditor", (data) => {
|
|
82
71
|
},
|
83
72
|
|
84
73
|
async save() {
|
85
|
-
this.
|
74
|
+
if (this.saving) return;
|
75
|
+
|
76
|
+
this.clearErrors();
|
86
77
|
this.saving = true;
|
87
78
|
|
88
|
-
if (this.
|
79
|
+
if (this.$refs.thumbnail) {
|
89
80
|
try {
|
90
81
|
await this._generateThumbnail();
|
91
82
|
} catch (error) {
|
@@ -96,24 +87,21 @@ export default CocoComponent("appSlideEditor", (data) => {
|
|
96
87
|
}
|
97
88
|
}
|
98
89
|
|
99
|
-
|
100
|
-
|
90
|
+
const form = this.$refs.form && this.$refs.form.querySelector("form");
|
91
|
+
|
92
|
+
if (form && form.dataset.submit !== "false") {
|
93
|
+
form.requestSubmit();
|
101
94
|
} else {
|
102
95
|
this.submitSuccess();
|
103
96
|
}
|
104
97
|
},
|
105
98
|
|
106
|
-
submitEnd(event) {
|
107
|
-
handler = wasSuccessful(event) ? "submitSuccess" : "submitError";
|
108
|
-
this[handler](event);
|
109
|
-
},
|
110
|
-
|
111
99
|
submitSuccess() {
|
112
100
|
this.history.clear();
|
113
101
|
this._fields.forEach((name) => (this.saved[name] = this[name]));
|
114
102
|
this.saving = false;
|
115
103
|
|
116
|
-
console.info("
|
104
|
+
console.info("Slide changes saved");
|
117
105
|
this.$dispatch("slide:save-end", { success: true });
|
118
106
|
},
|
119
107
|
|
@@ -127,22 +115,16 @@ export default CocoComponent("appSlideEditor", (data) => {
|
|
127
115
|
this._handleSaveError($event.detail.error, { event: $event });
|
128
116
|
},
|
129
117
|
|
130
|
-
|
131
|
-
|
132
|
-
if (image.file && image.file instanceof File) {
|
133
|
-
dataTransfer.items.add(image.file);
|
134
|
-
}
|
135
|
-
el.files = dataTransfer.files;
|
118
|
+
clearErrors() {
|
119
|
+
this.errors.length = 0;
|
136
120
|
},
|
137
121
|
|
138
|
-
input
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
bgImage: { "x-effect": "syncImageField($el, bgImage)" },
|
145
|
-
bgImagePurge: { ":checked": "!hasBgImage" },
|
122
|
+
syncFileInput(input, file) {
|
123
|
+
const dataTransfer = new DataTransfer();
|
124
|
+
if (file && file instanceof File) {
|
125
|
+
dataTransfer.items.add(file);
|
126
|
+
}
|
127
|
+
input.files = dataTransfer.files;
|
146
128
|
},
|
147
129
|
|
148
130
|
get hasBgImage() {
|
@@ -157,48 +139,18 @@ export default CocoComponent("appSlideEditor", (data) => {
|
|
157
139
|
return this.textColor.replace("#", "");
|
158
140
|
},
|
159
141
|
|
160
|
-
get slideStyles() {
|
161
|
-
return {
|
162
|
-
backgroundColor: this.bgColor,
|
163
|
-
color: this.textColor,
|
164
|
-
backgroundImage: this.hasBgImage
|
165
|
-
? `url('${this.bgImage.data}')`
|
166
|
-
: "none",
|
167
|
-
};
|
168
|
-
},
|
169
|
-
|
170
|
-
get slideClasses() {
|
171
|
-
return {
|
172
|
-
"slide-bg-dark": this.isDarkBg,
|
173
|
-
"slide-bg-light": !this.isDarkBg,
|
174
|
-
};
|
175
|
-
},
|
176
|
-
|
177
142
|
get isDarkBg() {
|
178
143
|
return this.hasBgImage || this.bgColor ? isDark(this.bgColor) : false;
|
179
144
|
},
|
180
145
|
|
181
|
-
get shouldGenerateThumbnail() {
|
182
|
-
return !!this.$refs.thumbnail;
|
183
|
-
},
|
184
|
-
|
185
146
|
get _fields() {
|
186
147
|
return Object.keys(initialData);
|
187
148
|
},
|
188
149
|
|
189
150
|
async _generateThumbnail() {
|
190
|
-
const screenshotSlide = this.$refs.screenshot.firstElementChild;
|
191
|
-
|
192
|
-
// The HTML-to-image library didn't like these styles being dynamically
|
193
|
-
// bound in the usual Alpine way so we have to manually apply them instead.
|
194
|
-
for (const [key, value] of Object.entries(this.slideStyles)) {
|
195
|
-
screenshotSlide.style[key] = value;
|
196
|
-
}
|
197
|
-
|
198
151
|
this.thumbnailFile = await captureElementScreenshot(
|
199
|
-
|
200
|
-
"slide-thumbnail"
|
201
|
-
thumbnailOpts
|
152
|
+
this.$refs.thumbnail.firstElementChild,
|
153
|
+
"slide-thumbnail"
|
202
154
|
);
|
203
155
|
|
204
156
|
console.info(
|
@@ -207,25 +159,42 @@ export default CocoComponent("appSlideEditor", (data) => {
|
|
207
159
|
);
|
208
160
|
},
|
209
161
|
|
210
|
-
// Called whenever a new thumbnail is generated,
|
211
|
-
// adds the thumbnail file to the hidden thumbnail file
|
212
|
-
// input upload field.
|
213
|
-
_syncThumbnailField() {
|
214
|
-
const dataTransfer = new DataTransfer();
|
215
|
-
if (this.thumbnailFile instanceof File) {
|
216
|
-
dataTransfer.items.add(this.thumbnailFile);
|
217
|
-
}
|
218
|
-
this.$refs.thumbnail.files = dataTransfer.files;
|
219
|
-
},
|
220
|
-
|
221
162
|
_handleSaveError(message = "Error saving slide", context = {}) {
|
222
163
|
this.errors.push({ message, context });
|
223
|
-
this.errors.forEach((err) => {
|
224
|
-
console.log(err.message);
|
225
|
-
});
|
226
164
|
this.saving = false;
|
227
165
|
|
228
166
|
this.$dispatch("slide:save-end", { success: false });
|
229
167
|
},
|
168
|
+
|
169
|
+
/* bindings */
|
170
|
+
|
171
|
+
slide: {
|
172
|
+
[":style"]() {
|
173
|
+
return {
|
174
|
+
backgroundColor: this.bgColor,
|
175
|
+
color: this.textColor,
|
176
|
+
backgroundImage: this.hasBgImage
|
177
|
+
? `url('${this.bgImage.data}')`
|
178
|
+
: "none",
|
179
|
+
};
|
180
|
+
},
|
181
|
+
[":class"]() {
|
182
|
+
return {
|
183
|
+
"slide-bg-dark": this.isDarkBg,
|
184
|
+
"slide-bg-light": !this.isDarkBg,
|
185
|
+
};
|
186
|
+
},
|
187
|
+
},
|
188
|
+
|
189
|
+
input: {
|
190
|
+
layout: { "x-model.fill": "layout" },
|
191
|
+
title: { "x-model.fill": "title" },
|
192
|
+
text1: { "x-model.fill": "text1" },
|
193
|
+
bgColor: { "x-model.fill": "bgColorHex" },
|
194
|
+
textColor: { "x-model.fill": "textColorHex" },
|
195
|
+
bgImage: { "x-effect": "syncFileInput($el, bgImage.file)" },
|
196
|
+
bgImagePurge: { ":checked": "!hasBgImage" },
|
197
|
+
thumbnailImage: { "x-effect": "syncFileInput($el, thumbnailFile)" },
|
198
|
+
},
|
230
199
|
};
|
231
200
|
});
|
@@ -6,8 +6,6 @@ module Coco
|
|
6
6
|
include Coco::BookHelper
|
7
7
|
include Coco::FormatHelper
|
8
8
|
|
9
|
-
renders_one :form
|
10
|
-
|
11
9
|
renders_one :title, ->(value = nil, **textarea_options) do
|
12
10
|
Coco::App::Elements::SeamlessTextarea.new(**textarea_options,
|
13
11
|
value: value,
|
@@ -37,9 +35,11 @@ module Coco
|
|
37
35
|
@bg_image_options = {src: src, **input_options}
|
38
36
|
end
|
39
37
|
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
def initialize(generate_thumbnail: true, **kwargs)
|
39
|
+
@generate_thumbnail = generate_thumbnail
|
40
|
+
end
|
41
|
+
|
42
|
+
def generate_thumbnail? = @generate_thumbnail
|
43
43
|
|
44
44
|
def slide_args
|
45
45
|
{
|
@@ -6,7 +6,7 @@
|
|
6
6
|
@apply transition-all overflow-hidden;
|
7
7
|
border-radius: 44px;
|
8
8
|
|
9
|
-
.button-content {
|
9
|
+
& > .button-element .button-content {
|
10
10
|
@apply font-semibold;
|
11
11
|
}
|
12
12
|
}
|
@@ -23,7 +23,7 @@
|
|
23
23
|
@apply bg-primary-700;
|
24
24
|
}
|
25
25
|
|
26
|
-
&[data-state="loading"] .button-icon {
|
26
|
+
&[data-state="loading"] > .button-element .button-icon {
|
27
27
|
@apply text-positive-300;
|
28
28
|
}
|
29
29
|
|
@@ -44,7 +44,7 @@
|
|
44
44
|
@apply bg-gray-blend-100;
|
45
45
|
}
|
46
46
|
|
47
|
-
&[data-state="loading"] .button-icon {
|
47
|
+
&[data-state="loading"] > .button-element .button-icon {
|
48
48
|
@apply text-positive-300;
|
49
49
|
}
|
50
50
|
|
@@ -65,7 +65,7 @@
|
|
65
65
|
@apply bg-gray-blend-100;
|
66
66
|
}
|
67
67
|
|
68
|
-
&[data-state="loading"] .button-icon {
|
68
|
+
&[data-state="loading"] > .button-element .button-icon {
|
69
69
|
@apply text-positive-300;
|
70
70
|
}
|
71
71
|
|
@@ -86,7 +86,7 @@
|
|
86
86
|
@apply bg-gray-blend-100;
|
87
87
|
}
|
88
88
|
|
89
|
-
&[data-state="loading"] .button-icon {
|
89
|
+
&[data-state="loading"] > .button-element .button-icon {
|
90
90
|
@apply text-positive-300;
|
91
91
|
}
|
92
92
|
|
@@ -106,7 +106,7 @@
|
|
106
106
|
@apply bg-negative-800;
|
107
107
|
}
|
108
108
|
|
109
|
-
&[data-state="loading"] .button-icon {
|
109
|
+
&[data-state="loading"] > .button-element .button-icon {
|
110
110
|
@apply text-negative-300;
|
111
111
|
}
|
112
112
|
|
@@ -126,7 +126,7 @@
|
|
126
126
|
@apply bg-gray-blend-100;
|
127
127
|
}
|
128
128
|
|
129
|
-
&[data-state="loading"] .button-icon {
|
129
|
+
&[data-state="loading"] > .button-element .button-icon {
|
130
130
|
@apply text-negative-300;
|
131
131
|
}
|
132
132
|
|
@@ -146,7 +146,7 @@
|
|
146
146
|
@apply bg-warning-800;
|
147
147
|
}
|
148
148
|
|
149
|
-
&[data-state="loading"] .button-icon {
|
149
|
+
&[data-state="loading"] > .button-element .button-icon {
|
150
150
|
@apply text-warning-300;
|
151
151
|
}
|
152
152
|
|
@@ -166,7 +166,7 @@
|
|
166
166
|
@apply bg-gray-blend-100;
|
167
167
|
}
|
168
168
|
|
169
|
-
&[data-state="loading"] .button-icon {
|
169
|
+
&[data-state="loading"] > .button-element .button-icon {
|
170
170
|
@apply text-warning-300;
|
171
171
|
}
|
172
172
|
|
@@ -186,7 +186,7 @@
|
|
186
186
|
@apply bg-info-800;
|
187
187
|
}
|
188
188
|
|
189
|
-
&[data-state="loading"] .button-icon {
|
189
|
+
&[data-state="loading"] > .button-element .button-icon {
|
190
190
|
@apply text-info-300;
|
191
191
|
}
|
192
192
|
|
@@ -206,7 +206,7 @@
|
|
206
206
|
@apply bg-gray-blend-100;
|
207
207
|
}
|
208
208
|
|
209
|
-
&[data-state="loading"] .button-icon {
|
209
|
+
&[data-state="loading"] > .button-element .button-icon {
|
210
210
|
@apply text-info-300;
|
211
211
|
}
|
212
212
|
|
@@ -41,7 +41,7 @@
|
|
41
41
|
|
42
42
|
/* loading */
|
43
43
|
|
44
|
-
&[data-state="loading"] .button-icon {
|
44
|
+
&[data-state="loading"] > .button-element .button-icon {
|
45
45
|
@apply animate-spin;
|
46
46
|
}
|
47
47
|
|
@@ -53,7 +53,7 @@
|
|
53
53
|
|
54
54
|
/* Icons */
|
55
55
|
|
56
|
-
&[data-icon-position="end"] {
|
56
|
+
&[data-icon-position="end"] > .button-element {
|
57
57
|
.button-content {
|
58
58
|
@apply order-1;
|
59
59
|
}
|
@@ -67,7 +67,7 @@
|
|
67
67
|
}
|
68
68
|
}
|
69
69
|
|
70
|
-
&.with-icon[data-collapsed="true"] {
|
70
|
+
&.with-icon[data-collapsed="true"] > .button-element {
|
71
71
|
.button-content {
|
72
72
|
display: none;
|
73
73
|
}
|