coveragebook_components 0.5.1 → 0.5.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 +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
|
}
|