spina 2.4.0 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of spina might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/app/assets/javascripts/spina/application.js +1 -1
- data/app/assets/javascripts/spina/controllers/application.js +11 -0
- data/app/assets/javascripts/spina/controllers/embed_controller.js +16 -0
- data/app/assets/javascripts/spina/controllers/embed_tag_controller.js +16 -0
- data/app/assets/javascripts/spina/controllers/index.js +5 -0
- data/app/assets/javascripts/spina/controllers/trix_controller.js +12 -2
- data/app/assets/stylesheets/spina/_tailwind.css +18 -5
- data/app/assets/stylesheets/spina/tailwind/custom.css +13 -5
- data/app/components/spina/forms/trix_toolbar_component.html.erb +26 -15
- data/app/controllers/spina/admin/embeds_controller.rb +36 -0
- data/app/helpers/spina/admin/icons_helper.rb +2 -2
- data/app/helpers/spina/spina_helper.rb +3 -2
- data/app/models/spina/embeds/base.rb +7 -0
- data/app/models/spina/embeds/button.rb +13 -0
- data/app/models/spina/embeds/vimeo.rb +39 -0
- data/app/models/spina/embeds/youtube.rb +39 -0
- data/app/models/spina/page.rb +6 -0
- data/app/presenters/spina/content_presenter.rb +1 -1
- data/app/presenters/spina/rich_text_presenter.rb +45 -0
- data/app/views/spina/admin/embeds/new.html.erb +47 -0
- data/app/views/spina/admin/shared/_flash.html.erb +2 -2
- data/app/views/spina/embeds/buttons/_button.html.erb +3 -0
- data/app/views/spina/embeds/buttons/_button_fields.html.erb +14 -0
- data/app/views/spina/embeds/buttons/_trix_button.html.erb +3 -0
- data/app/views/spina/embeds/vimeos/_thumbnail.html.erb +6 -0
- data/app/views/spina/embeds/vimeos/_vimeo.html.erb +1 -0
- data/app/views/spina/embeds/vimeos/_vimeo_fields.html.erb +9 -0
- data/app/views/spina/embeds/youtubes/_thumbnail.html.erb +6 -0
- data/app/views/spina/embeds/youtubes/_youtube.html.erb +1 -0
- data/app/views/spina/embeds/youtubes/_youtube_fields.html.erb +9 -0
- data/config/initializers/importmap.rb +1 -1
- data/config/locales/en.yml +18 -0
- data/config/routes.rb +2 -0
- data/lib/generators/spina/templates/config/initializers/themes/default.rb +3 -0
- data/lib/generators/spina/templates/config/initializers/themes/demo.rb +3 -0
- data/lib/spina/embeddable.rb +48 -0
- data/lib/spina/embeds/trix_conversion.rb +41 -0
- data/lib/spina/embeds.rb +11 -0
- data/lib/spina/engine.rb +6 -4
- data/lib/spina/part.rb +10 -2
- data/lib/spina/railtie.rb +10 -0
- data/lib/spina/theme.rb +12 -1
- data/lib/spina/theme_reloader.rb +20 -0
- data/lib/spina/version.rb +1 -1
- data/lib/spina.rb +4 -0
- data/lib/tasks/spina_tasks.rake +1 -1
- metadata +36 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6eddb2bbef87fd0d66a6ca49f2234bf75a659a67ddf1ccbf95b5ccb0fc385332
|
4
|
+
data.tar.gz: 283ae2a27280cd16c66927ce8aa82210112372a8bc873d25519ee7cf3e3b8b1b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 41ba06425dd468e816f32031eef4eaa6bafef3defb437274c980d96d9e9dcc130dcb975942dfc0171bcd0883b07efb3a4037610c9c843f9b7ad936c3afb88e57
|
7
|
+
data.tar.gz: b973bea94d9d22268c076b7023de7dc617876a0064ac6cb47c2513499b5e082c0556a7f991573088c3a228d53c4ee4453f0f1c44756dbe4580c0d48c3be37617
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
2
|
+
|
3
|
+
export default class extends Controller {
|
4
|
+
static get targets() {
|
5
|
+
return [ "html" ]
|
6
|
+
}
|
7
|
+
|
8
|
+
insertEmbeddable(event) {
|
9
|
+
this.trixEditor.insertEmbeddable(event.detail.html)
|
10
|
+
}
|
11
|
+
|
12
|
+
get trixEditor() {
|
13
|
+
return document.getElementById(this.element.dataset.trixTarget).trix
|
14
|
+
}
|
15
|
+
|
16
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
2
|
+
|
3
|
+
export default class extends Controller {
|
4
|
+
|
5
|
+
connect() {
|
6
|
+
let event = new CustomEvent("embed-tag:embedded", this.eventOptions)
|
7
|
+
this.element.dispatchEvent(event)
|
8
|
+
}
|
9
|
+
|
10
|
+
get eventOptions() {
|
11
|
+
let clone = this.element.cloneNode(true)
|
12
|
+
clone.removeAttribute("data-controller")
|
13
|
+
return {bubbles: true, detail: {html: clone.outerHTML}}
|
14
|
+
}
|
15
|
+
|
16
|
+
}
|
@@ -5,11 +5,13 @@ export default class extends Controller {
|
|
5
5
|
return [ "editor", "imageFields", "altField" ]
|
6
6
|
}
|
7
7
|
|
8
|
-
connect() {
|
8
|
+
connect() {
|
9
|
+
this.element[this.identifier] = this
|
10
|
+
|
9
11
|
this.editorTarget.addEventListener("trix-selection-change", function(event) {
|
10
12
|
if (this.mutableImageAttachment) {
|
11
13
|
this.imageFieldsTarget.classList.remove("hidden")
|
12
|
-
let position = this.mutableImageAttachment.querySelector("img").offsetTop + this.mutableImageAttachment.querySelector("img").offsetHeight
|
14
|
+
let position = this.mutableImageAttachment.querySelector("img").offsetTop + this.mutableImageAttachment.querySelector("img").offsetHeight
|
13
15
|
this.imageFieldsTarget.style.top = `${position}px`
|
14
16
|
this.altFieldTarget.value = this.currentAltText
|
15
17
|
} else {
|
@@ -18,6 +20,14 @@ export default class extends Controller {
|
|
18
20
|
}.bind(this))
|
19
21
|
}
|
20
22
|
|
23
|
+
insertEmbeddable(html) {
|
24
|
+
let embeddable = new Trix.Attachment({
|
25
|
+
content: html,
|
26
|
+
contentType: "application/vnd+spina.embed+html"})
|
27
|
+
|
28
|
+
this.editor.insertAttachment(embeddable)
|
29
|
+
}
|
30
|
+
|
21
31
|
preventSubmission(event) {
|
22
32
|
if (event.key === 'Enter') event.preventDefault() // Prevent form submit from alt text fields
|
23
33
|
}
|
@@ -2342,18 +2342,20 @@ trix-editor {
|
|
2342
2342
|
user-select: none
|
2343
2343
|
}
|
2344
2344
|
figure.attachment {
|
2345
|
+
margin: 0px;
|
2346
|
+
display: inline-block
|
2347
|
+
}
|
2348
|
+
figure.attachment[data-trix-content-type="Spina::Image"] {
|
2345
2349
|
max-height: 150px;
|
2346
2350
|
max-width: 200px;
|
2347
|
-
margin: 0px;
|
2348
|
-
display: inline-block;
|
2349
2351
|
}
|
2350
|
-
figure.attachment img {
|
2352
|
+
figure.attachment[data-trix-content-type="Spina::Image"] img {
|
2351
2353
|
margin: 0px;
|
2352
2354
|
border-radius: 0.375rem;
|
2353
2355
|
-o-object-fit: contain;
|
2354
2356
|
object-fit: contain;
|
2355
2357
|
}
|
2356
|
-
figure.attachment [data-label]:after {
|
2358
|
+
figure.attachment[data-trix-content-type="Spina::Image"] [data-label]:after {
|
2357
2359
|
content: attr(data-label);
|
2358
2360
|
margin-top: 0.25rem;
|
2359
2361
|
display: flex;
|
@@ -2367,7 +2369,7 @@ trix-editor {
|
|
2367
2369
|
--tw-text-opacity: 1;
|
2368
2370
|
color: rgba(107, 114, 128, var(--tw-text-opacity));
|
2369
2371
|
}
|
2370
|
-
figure[data-trix-mutable].attachment img {
|
2372
|
+
figure[data-trix-mutable].attachment[data-trix-content-type="Spina::Image"] img {
|
2371
2373
|
--tw-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
2372
2374
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
2373
2375
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
@@ -2376,6 +2378,17 @@ trix-editor {
|
|
2376
2378
|
--tw-ring-opacity: 1;
|
2377
2379
|
--tw-ring-color: rgba(121, 122, 184, var(--tw-ring-opacity))
|
2378
2380
|
}
|
2381
|
+
figure[data-trix-mutable][data-trix-content-type="application/vnd+spina.embed+html"].attachment > spina-embed {
|
2382
|
+
display: block;
|
2383
|
+
border-radius: 0.375rem;
|
2384
|
+
--tw-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
2385
|
+
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
2386
|
+
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
2387
|
+
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
2388
|
+
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
2389
|
+
--tw-ring-opacity: 1;
|
2390
|
+
--tw-ring-color: rgba(121, 122, 184, var(--tw-ring-opacity));
|
2391
|
+
}
|
2379
2392
|
figure .attachment__caption {
|
2380
2393
|
display: none
|
2381
2394
|
}
|
@@ -154,25 +154,33 @@
|
|
154
154
|
[data-trix-mutable]:not(.attachment__captain-editor) {
|
155
155
|
@apply select-none
|
156
156
|
}
|
157
|
-
|
157
|
+
|
158
158
|
figure.attachment {
|
159
|
+
@apply m-0 inline-block
|
160
|
+
}
|
161
|
+
|
162
|
+
figure.attachment[data-trix-content-type="Spina::Image"] {
|
159
163
|
max-height: 150px;
|
160
164
|
max-width: 200px;
|
161
|
-
@apply m-0 inline-block;
|
162
165
|
}
|
163
166
|
|
164
|
-
figure.attachment img {
|
167
|
+
figure.attachment[data-trix-content-type="Spina::Image"] img {
|
165
168
|
@apply m-0 rounded-md object-contain;
|
166
169
|
}
|
167
170
|
|
168
|
-
figure.attachment [data-label]:after {
|
171
|
+
figure.attachment[data-trix-content-type="Spina::Image"] [data-label]:after {
|
169
172
|
content: attr(data-label);
|
170
173
|
@apply italic text-gray-500 h-8 flex items-center px-2 mt-1 text-sm;
|
171
174
|
}
|
172
175
|
|
173
|
-
figure[data-trix-mutable].attachment img {
|
176
|
+
figure[data-trix-mutable].attachment[data-trix-content-type="Spina::Image"] img {
|
174
177
|
@apply shadow-lg ring ring-spina-light
|
175
178
|
}
|
179
|
+
|
180
|
+
figure[data-trix-mutable][data-trix-content-type="application/vnd+spina.embed+html"].attachment > spina-embed {
|
181
|
+
@apply block;
|
182
|
+
@apply shadow-lg ring ring-spina-light rounded-md;
|
183
|
+
}
|
176
184
|
|
177
185
|
figure .attachment__caption {
|
178
186
|
@apply hidden
|
@@ -1,57 +1,68 @@
|
|
1
1
|
<div class="relative sticky top-0 pt-4 bg-white trix-toolbar" id="<%= @trix_id %>">
|
2
2
|
<div class="flex items-center flex-wrap" data-controller="reveal">
|
3
3
|
<div class="flex items-center bg-gray-200 rounded overflow-hidden mb-3 mr-3">
|
4
|
-
<button type="button" class="text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="bold" data-trix-key="b" title="${Trix.config.lang.bold}" tabindex="-1">
|
4
|
+
<button type="button" class="hover:bg-gray-300 text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="bold" data-trix-key="b" title="${Trix.config.lang.bold}" tabindex="-1">
|
5
5
|
<svg class="w-4 h-4" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M333.49 238a122 122 0 0 0 27-65.21C367.87 96.49 308 32 233.42 32H34a16 16 0 0 0-16 16v48a16 16 0 0 0 16 16h31.87v288H34a16 16 0 0 0-16 16v48a16 16 0 0 0 16 16h209.32c70.8 0 134.14-51.75 141-122.4 4.74-48.45-16.39-92.06-50.83-119.6zM145.66 112h87.76a48 48 0 0 1 0 96h-87.76zm87.76 288h-87.76V288h87.76a56 56 0 0 1 0 112z"/></svg>
|
6
6
|
</button>
|
7
|
-
<button type="button" class="text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="italic" data-trix-key="i" title="${Trix.config.lang.italic}" tabindex="-1">
|
7
|
+
<button type="button" class="hover:bg-gray-300 text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="italic" data-trix-key="i" title="${Trix.config.lang.italic}" tabindex="-1">
|
8
8
|
<svg class="w-4 h-4" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M320 48v32a16 16 0 0 1-16 16h-62.76l-80 320H208a16 16 0 0 1 16 16v32a16 16 0 0 1-16 16H16a16 16 0 0 1-16-16v-32a16 16 0 0 1 16-16h62.76l80-320H112a16 16 0 0 1-16-16V48a16 16 0 0 1 16-16h192a16 16 0 0 1 16 16z"/></svg>
|
9
9
|
</button>
|
10
|
-
<button type="button" class="text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="<%=t 'spina.wysiwyg.link' %>" tabindex="-1" data-action="reveal#toggle">
|
10
|
+
<button type="button" class="hover:bg-gray-300 text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="<%=t 'spina.wysiwyg.link' %>" tabindex="-1" data-action="reveal#toggle">
|
11
11
|
<svg class="w-4 h-4" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg>
|
12
12
|
</button>
|
13
13
|
</div>
|
14
14
|
|
15
15
|
<div class="flex items-center bg-gray-200 rounded overflow-hidden mr-3 mb-3" data-trix-button-group="block-tools">
|
16
|
-
<button type="button" class="text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="heading1" title="${Trix.config.lang.heading1}" tabindex="-1">
|
16
|
+
<button type="button" class="hover:bg-gray-300 text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="heading1" title="${Trix.config.lang.heading1}" tabindex="-1">
|
17
17
|
<svg class="w-4 h-4" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M304 96h-98.94A13.06 13.06 0 0 0 192 109.06v21.88A13.06 13.06 0 0 0 205.06 144H232v88H88v-88h26.94A13.06 13.06 0 0 0 128 130.94V112a16 16 0 0 0-16-16H16a16 16 0 0 0-16 16v18.94A13.06 13.06 0 0 0 13.06 144H40v224H13.06A13.06 13.06 0 0 0 0 381.06V400a16 16 0 0 0 16 16h98.94A13.06 13.06 0 0 0 128 402.94v-21.88A13.06 13.06 0 0 0 114.94 368H88v-88h144v88h-26.94A13.06 13.06 0 0 0 192 381.06V400a16 16 0 0 0 16 16h96a16 16 0 0 0 16-16v-18.94A13.06 13.06 0 0 0 306.94 368H280V144h26.94A13.06 13.06 0 0 0 320 130.94V112a16 16 0 0 0-16-16zm256 272h-56V120a24 24 0 0 0-24-24h-24a24 24 0 0 0-21.44 13.26l-24 48A24 24 0 0 0 432 192h24v176h-56a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h160a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16z"/></svg>
|
18
18
|
</button>
|
19
|
-
<button type="button" class="text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="heading2" title="${Trix.config.lang.heading2}" tabindex="-1">
|
19
|
+
<button type="button" class="hover:bg-gray-300 text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="heading2" title="${Trix.config.lang.heading2}" tabindex="-1">
|
20
20
|
<svg class="w-4 h-4" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M304 96h-98.94A13.06 13.06 0 0 0 192 109.06v21.88A13.06 13.06 0 0 0 205.06 144H232v88H88v-88h26.94A13.06 13.06 0 0 0 128 130.94V112a16 16 0 0 0-16-16H16a16 16 0 0 0-16 16v18.94A13.06 13.06 0 0 0 13.06 144H40v224H13.06A13.06 13.06 0 0 0 0 381.06V400a16 16 0 0 0 16 16h98.94A13.06 13.06 0 0 0 128 402.94v-21.88A13.06 13.06 0 0 0 114.94 368H88v-88h144v88h-26.94A13.06 13.06 0 0 0 192 381.06V400a16 16 0 0 0 16 16h96a16 16 0 0 0 16-16v-18.94A13.06 13.06 0 0 0 306.94 368H280V144h26.94A13.06 13.06 0 0 0 320 130.94V112a16 16 0 0 0-16-16zm244.14 272.13H410.82c8.52-60.35 146-79.28 146-179.31C556.8 134.17 515 96 455.05 96a114.71 114.71 0 0 0-97.92 55.05 11.81 11.81 0 0 0 3.58 15.95L382 181.23a11.89 11.89 0 0 0 16.27-3c13-18.23 31.58-31.35 53.72-31.35 29.57 0 49.43 18.08 49.43 45 0 67-149.45 84-149.45 195.49a137.14 137.14 0 0 0 1.39 18.42 12.18 12.18 0 0 0 11.8 10.21h183A11.85 11.85 0 0 0 560 404.18V380a11.85 11.85 0 0 0-11.86-11.87z"/></svg>
|
21
21
|
</button>
|
22
|
-
<button type="button" class="text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="heading3" title="${Trix.config.lang.heading3}" tabindex="-1">
|
22
|
+
<button type="button" class="hover:bg-gray-300 text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="heading3" title="${Trix.config.lang.heading3}" tabindex="-1">
|
23
23
|
<svg class="w-4 h-4" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M480.07 219.78l75.39-85.88a11.82 11.82 0 0 0 2.93-7.76v-18.32A11.89 11.89 0 0 0 546.44 96H379.87a11.88 11.88 0 0 0-11.94 11.82V132a11.88 11.88 0 0 0 11.94 11.83s102.44-.11 106-.25c-2.77 2.88-74.12 85.58-74.12 85.58a11.67 11.67 0 0 0-1.86 12.38l6.71 15.3a12.94 12.94 0 0 0 10.93 7.16h17.08c48.61 0 65.85 27.23 65.85 50.56 0 28.57-24.58 50.13-57.17 50.13-24 0-46.88-10.46-65.29-26.89a12 12 0 0 0-17.76 1.81l-16 22a11.73 11.73 0 0 0 1.4 15.41c24.6 23.34 60.62 39 99.38 39 64.2 0 109.86-46.22 109.86-103.17.01-51.1-36.73-84.17-84.81-93.07zM304 96h-98.94A13.06 13.06 0 0 0 192 109.06v21.88A13.06 13.06 0 0 0 205.06 144H232v88H88v-88h26.94A13.06 13.06 0 0 0 128 130.94V112a16 16 0 0 0-16-16H16a16 16 0 0 0-16 16v18.94A13.06 13.06 0 0 0 13.06 144H40v224H13.06A13.06 13.06 0 0 0 0 381.06V400a16 16 0 0 0 16 16h98.94A13.06 13.06 0 0 0 128 402.94v-21.88A13.06 13.06 0 0 0 114.94 368H88v-88h144v88h-26.94A13.06 13.06 0 0 0 192 381.06V400a16 16 0 0 0 16 16h96a16 16 0 0 0 16-16v-18.94A13.06 13.06 0 0 0 306.94 368H280V144h26.94A13.06 13.06 0 0 0 320 130.94V112a16 16 0 0 0-16-16z"/></svg>
|
24
24
|
</button>
|
25
|
-
<button type="button" class="text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="heading4" title="${Trix.config.lang.heading4}" tabindex="-1">
|
25
|
+
<button type="button" class="hover:bg-gray-300 text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="heading4" title="${Trix.config.lang.heading4}" tabindex="-1">
|
26
26
|
<svg class="w-4 h-4" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M304 96h-98.94A13.06 13.06 0 0 0 192 109.06v21.88A13.06 13.06 0 0 0 205.06 144H232v88H88v-88h26.94A13.06 13.06 0 0 0 128 130.94V112a16 16 0 0 0-16-16H16a16 16 0 0 0-16 16v18.94A13.06 13.06 0 0 0 13.06 144H40v224H13.06A13.06 13.06 0 0 0 0 381.06V400a16 16 0 0 0 16 16h98.94A13.06 13.06 0 0 0 128 402.94v-21.88A13.06 13.06 0 0 0 114.94 368H88v-88h144v88h-26.94A13.06 13.06 0 0 0 192 381.06V400a16 16 0 0 0 16 16h96a16 16 0 0 0 16-16v-18.94A13.06 13.06 0 0 0 306.94 368H280V144h26.94A13.06 13.06 0 0 0 320 130.94V112a16 16 0 0 0-16-16zm256 136h-16V112a16 16 0 0 0-16-16h-16a16 16 0 0 0-16 16v120h-96V112a16 16 0 0 0-16-16h-16a16 16 0 0 0-16 16v136a32 32 0 0 0 32 32h112v120a16 16 0 0 0 16 16h16a16 16 0 0 0 16-16V280h16a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16z"/></svg>
|
27
27
|
</button>
|
28
28
|
</div>
|
29
29
|
|
30
|
-
<div class="flex items-center bg-gray-200 rounded overflow-hidden mr-3 mb-3">
|
31
|
-
|
30
|
+
<div class="flex items-center bg-gray-200 rounded overflow-hidden mr-3 mb-3">
|
31
|
+
|
32
|
+
<%= link_to helpers.spina.admin_media_picker_path(target: "insert_#{@trix_id}"), class: "hover:bg-gray-300 text-gray-700 w-9 h-9 flex items-center justify-center", data: {turbo_frame: "modal"} do %>
|
32
33
|
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
33
34
|
<path fill-rule="evenodd" d="M4 3a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V5a2 2 0 00-2-2H4zm12 12H4l4-8 3 6 2-4 3 6z" clip-rule="evenodd" />
|
34
35
|
</svg>
|
35
36
|
<% end %>
|
36
37
|
|
37
|
-
|
38
|
+
<% if helpers.current_theme.embeds.any? %>
|
39
|
+
<%= link_to helpers.spina.new_admin_embed_path(target: "insert_#{@trix_id}"), class: "hover:bg-gray-300 text-gray-700 w-9 h-9 flex items-center justify-center", data: {turbo_frame: "modal"} do %>
|
40
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
41
|
+
<path d="M5 3a2 2 0 00-2 2v2a2 2 0 002 2h2a2 2 0 002-2V5a2 2 0 00-2-2H5zM5 11a2 2 0 00-2 2v2a2 2 0 002 2h2a2 2 0 002-2v-2a2 2 0 00-2-2H5zM11 5a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V5zM14 11a1 1 0 011 1v1h1a1 1 0 110 2h-1v1a1 1 0 11-2 0v-1h-1a1 1 0 110-2h1v-1a1 1 0 011-1z" />
|
42
|
+
</svg>
|
43
|
+
<% end %>
|
44
|
+
<% end %>
|
45
|
+
</div>
|
46
|
+
|
47
|
+
<div class="flex items-center bg-gray-200 rounded overflow-hidden mr-3 mb-3">
|
48
|
+
<button type="button" class="hover:bg-gray-300 text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="quote" title="${Trix.config.lang.quote}" tabindex="-1">
|
38
49
|
<svg class="w-4 h-4" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M464 32H336c-26.5 0-48 21.5-48 48v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48zm-288 0H48C21.5 32 0 53.5 0 80v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48z"/></svg>
|
39
50
|
</button>
|
40
|
-
<button type="button" class="text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="code" title="${Trix.config.lang.code}" tabindex="-1">
|
51
|
+
<button type="button" class="hover:bg-gray-300 text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="code" title="${Trix.config.lang.code}" tabindex="-1">
|
41
52
|
<svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
42
53
|
<path fill-rule="evenodd" d="M12.316 3.051a1 1 0 01.633 1.265l-4 12a1 1 0 11-1.898-.632l4-12a1 1 0 011.265-.633zM5.707 6.293a1 1 0 010 1.414L3.414 10l2.293 2.293a1 1 0 11-1.414 1.414l-3-3a1 1 0 010-1.414l3-3a1 1 0 011.414 0zm8.586 0a1 1 0 011.414 0l3 3a1 1 0 010 1.414l-3 3a1 1 0 11-1.414-1.414L16.586 10l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" />
|
43
54
|
</svg>
|
44
55
|
</button>
|
45
|
-
<button type="button" class="trix-button trix-button--icon trix-button--icon-bullet-list text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="bullet" title="${Trix.config.lang.bullets}" tabindex="-1">
|
56
|
+
<button type="button" class="hover:bg-gray-300 trix-button trix-button--icon trix-button--icon-bullet-list text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="bullet" title="${Trix.config.lang.bullets}" tabindex="-1">
|
46
57
|
<svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 512 512"><path d="M48 368a48 48 0 1 0 48 48 48 48 0 0 0-48-48zm0-160a48 48 0 1 0 48 48 48 48 0 0 0-48-48zm0-160a48 48 0 1 0 48 48 48 48 0 0 0-48-48zm448 24H176a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16V88a16 16 0 0 0-16-16zm0 160H176a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16zm0 160H176a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16z"/></svg>
|
47
58
|
</button>
|
48
|
-
<button type="button" class="trix-button trix-button--icon trix-button--icon-number-list text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="number" title="${Trix.config.lang.numbers}" tabindex="-1">
|
59
|
+
<button type="button" class="hover:bg-gray-300 trix-button trix-button--icon trix-button--icon-number-list text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-attribute="number" title="${Trix.config.lang.numbers}" tabindex="-1">
|
49
60
|
<svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 512 512"><path d="M61.77 401l17.5-20.15a19.92 19.92 0 0 0 5.07-14.19v-3.31C84.34 356 80.5 352 73 352H16a8 8 0 0 0-8 8v16a8 8 0 0 0 8 8h22.84a154.82 154.82 0 0 0-11 12.31l-5.61 7c-4 5.07-5.25 10.13-2.8 14.88l1.05 1.93c3 5.76 6.3 7.88 12.25 7.88h4.73c10.33 0 15.94 2.44 15.94 9.09 0 4.72-4.2 8.22-14.36 8.22a41.54 41.54 0 0 1-15.47-3.12c-6.49-3.88-11.74-3.5-15.6 3.12l-5.59 9.31c-3.73 6.13-3.2 11.72 2.62 15.94 7.71 4.69 20.39 9.44 37 9.44 34.16 0 48.5-22.75 48.5-44.12-.03-14.38-9.12-29.76-28.73-34.88zM496 392H176a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16zm0-320H176a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16V88a16 16 0 0 0-16-16zm0 160H176a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16zM16 160h64a8 8 0 0 0 8-8v-16a8 8 0 0 0-8-8H64V40a8 8 0 0 0-8-8H32a8 8 0 0 0-7.14 4.42l-8 16A8 8 0 0 0 24 64h8v64H16a8 8 0 0 0-8 8v16a8 8 0 0 0 8 8zm-3.9 160H80a8 8 0 0 0 8-8v-16a8 8 0 0 0-8-8H41.33c3.28-10.29 48.33-18.68 48.33-56.44 0-29.06-25-39.56-44.47-39.56-21.36 0-33.8 10-40.45 18.75-4.38 5.59-3 10.84 2.79 15.37l8.58 6.88c5.61 4.56 11 2.47 16.13-2.44a13.4 13.4 0 0 1 9.45-3.84c3.33 0 9.28 1.56 9.28 8.75C51 248.19 0 257.31 0 304.59v4C0 316 5.08 320 12.1 320z"/></svg>
|
50
61
|
</button>
|
51
|
-
<button type="button" class="trix-button trix-button--icon trix-button--icon-decrease-nesting-level text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-action="decreaseNestingLevel" title="${Trix.config.lang.outdent}" tabindex="-1">
|
62
|
+
<button type="button" class="hover:bg-gray-300 trix-button trix-button--icon trix-button--icon-decrease-nesting-level text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-action="decreaseNestingLevel" title="${Trix.config.lang.outdent}" tabindex="-1">
|
52
63
|
<svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 448 512"><path d="M100.69 363.29c10 10 27.31 2.93 27.31-11.31V160c0-14.32-17.33-21.31-27.31-11.31l-96 96a16 16 0 0 0 0 22.62zM432 424H16a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16zm3.17-128H204.83A12.82 12.82 0 0 0 192 308.83v22.34A12.82 12.82 0 0 0 204.83 344h230.34A12.82 12.82 0 0 0 448 331.17v-22.34A12.82 12.82 0 0 0 435.17 296zM432 40H16A16 16 0 0 0 0 56v16a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V56a16 16 0 0 0-16-16zm3.17 128H204.83A12.82 12.82 0 0 0 192 180.83v22.34A12.82 12.82 0 0 0 204.83 216h230.34A12.82 12.82 0 0 0 448 203.17v-22.34A12.82 12.82 0 0 0 435.17 168z"/></svg>
|
53
64
|
</button>
|
54
|
-
<button type="button" class="trix-button trix-button--icon trix-button--icon-increase-nesting-level text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-action="increaseNestingLevel" title="${Trix.config.lang.indent}" tabindex="-1">
|
65
|
+
<button type="button" class="hover:bg-gray-300 trix-button trix-button--icon trix-button--icon-increase-nesting-level text-gray-700 w-9 h-9 flex items-center justify-center" data-trix-action="increaseNestingLevel" title="${Trix.config.lang.indent}" tabindex="-1">
|
55
66
|
<svg class="w-4 h-4" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M432 424H16a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16zM27.31 363.3l96-96a16 16 0 0 0 0-22.62l-96-96C17.27 138.66 0 145.78 0 160v192c0 14.31 17.33 21.3 27.31 11.3zM435.17 168H204.83A12.82 12.82 0 0 0 192 180.83v22.34A12.82 12.82 0 0 0 204.83 216h230.34A12.82 12.82 0 0 0 448 203.17v-22.34A12.82 12.82 0 0 0 435.17 168zM432 48H16A16 16 0 0 0 0 64v16a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V64a16 16 0 0 0-16-16zm3.17 248H204.83A12.82 12.82 0 0 0 192 308.83v22.34A12.82 12.82 0 0 0 204.83 344h230.34A12.82 12.82 0 0 0 448 331.17v-22.34A12.82 12.82 0 0 0 435.17 296z"/></svg>
|
56
67
|
</button>
|
57
68
|
</div>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Spina
|
2
|
+
module Admin
|
3
|
+
class EmbedsController < AdminController
|
4
|
+
|
5
|
+
def new
|
6
|
+
@embeddable = (Spina::Embeds.constantize(embed_type) || embeddables.first).new
|
7
|
+
end
|
8
|
+
|
9
|
+
def create
|
10
|
+
@embeddable = Spina::Embeds.constantize(embed_type).new(embed_params)
|
11
|
+
|
12
|
+
if @embeddable.valid?
|
13
|
+
render turbo_stream: turbo_stream.update(:trix_attachment_html, @embeddable.to_trix_attachment)
|
14
|
+
else
|
15
|
+
render :new, status: :unprocessable_entity
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def embeddables
|
22
|
+
@embeddables ||= current_theme.embeddables
|
23
|
+
end
|
24
|
+
helper_method :embeddables
|
25
|
+
|
26
|
+
def embed_type
|
27
|
+
params[:embed_type]
|
28
|
+
end
|
29
|
+
|
30
|
+
def embed_params
|
31
|
+
params.require(:embeddable).permit!
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -8,7 +8,7 @@ module Spina::Admin
|
|
8
8
|
|
9
9
|
def heroicon(name, style: :outline, **options)
|
10
10
|
file = read_file(Spina::Engine.root.join("app/assets/icons/heroicons", style.to_s, "#{name}.svg"))
|
11
|
-
|
11
|
+
return "" if file.nil?
|
12
12
|
doc = Nokogiri::XML(file)
|
13
13
|
svg = doc.root
|
14
14
|
svg[:class] = options[:class]
|
@@ -18,7 +18,7 @@ module Spina::Admin
|
|
18
18
|
private
|
19
19
|
|
20
20
|
def read_file(path)
|
21
|
-
File.exist?(path)
|
21
|
+
return nil unless File.exist?(path)
|
22
22
|
File.read(path)
|
23
23
|
end
|
24
24
|
|
@@ -1,10 +1,11 @@
|
|
1
1
|
module Spina::SpinaHelper
|
2
2
|
|
3
|
-
def spina_importmap_tags(entry_point = "application")
|
3
|
+
def spina_importmap_tags(entry_point = "application", shim: true)
|
4
4
|
safe_join [
|
5
5
|
javascript_inline_importmap_tag(Spina.config.importmap.to_json(resolver: self)),
|
6
6
|
javascript_importmap_module_preload_tags(Spina.config.importmap),
|
7
|
-
|
7
|
+
(javascript_importmap_shim_nonce_configuration_tag if shim),
|
8
|
+
(javascript_importmap_shim_tag if shim),
|
8
9
|
javascript_import_module_tag(entry_point)
|
9
10
|
], "\n"
|
10
11
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Spina::Embeds
|
4
|
+
class Vimeo < Base
|
5
|
+
attributes :url
|
6
|
+
|
7
|
+
heroicon "video-camera"
|
8
|
+
|
9
|
+
REGEX = /(https?:\/\/)?(www.)?(player.)?vimeo.com\/([a-z]*\/)*([0-9]{6,11})[?]?.*/
|
10
|
+
|
11
|
+
validates :url, presence: true, format: {with: REGEX}
|
12
|
+
|
13
|
+
def id
|
14
|
+
REGEX.match(url).try(:[], 5)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Get title from Vimeo API (remote call)
|
18
|
+
def remote_title
|
19
|
+
get_vimeo_json&.dig(0, "title")
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_trix_partial_path
|
23
|
+
"spina/embeds/vimeos/thumbnail"
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def get_vimeo_json
|
29
|
+
uri = URI("https://vimeo.com/api/v2/video/#{id}.json")
|
30
|
+
response = Net::HTTP.get(uri)
|
31
|
+
begin
|
32
|
+
JSON.parse(response)
|
33
|
+
rescue
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Spina::Embeds
|
4
|
+
class Youtube < Base
|
5
|
+
attributes :url
|
6
|
+
|
7
|
+
heroicon "video-camera"
|
8
|
+
|
9
|
+
REGEX = /(?:youtube(?:-nocookie)?\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})/
|
10
|
+
|
11
|
+
validates :url, presence: true, format: {with: REGEX}
|
12
|
+
|
13
|
+
def id
|
14
|
+
REGEX.match(url).try(:[], 1)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Get title from Youtube API (remote call)
|
18
|
+
def remote_title
|
19
|
+
get_youtube_json&.dig("title")
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_trix_partial_path
|
23
|
+
"spina/embeds/youtubes/thumbnail"
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def get_youtube_json
|
29
|
+
uri = URI("https://www.youtube.com/oembed?url=http://youtube.com/watch?v=#{id}&format=json")
|
30
|
+
response = Net::HTTP.get(uri)
|
31
|
+
begin
|
32
|
+
JSON.parse(response)
|
33
|
+
rescue
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
data/app/models/spina/page.rb
CHANGED
@@ -26,6 +26,8 @@ module Spina
|
|
26
26
|
scope :sorted, -> { order(:position) }
|
27
27
|
scope :live, -> { active.where(draft: false) }
|
28
28
|
scope :in_menu, -> { where(show_in_menu: true) }
|
29
|
+
|
30
|
+
before_create :set_default_position
|
29
31
|
|
30
32
|
# Copy resource from parent
|
31
33
|
before_save :set_resource_from_parent, if: -> { parent.present? }
|
@@ -102,6 +104,10 @@ module Spina
|
|
102
104
|
end
|
103
105
|
|
104
106
|
private
|
107
|
+
|
108
|
+
def set_default_position
|
109
|
+
self.position ||= self.class.maximum(:position).to_i.next
|
110
|
+
end
|
105
111
|
|
106
112
|
def set_resource_from_parent
|
107
113
|
self.resource_id = parent.resource_id
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Spina
|
2
|
+
class RichTextPresenter
|
3
|
+
attr_reader :html, :view_context
|
4
|
+
|
5
|
+
EMBED_CONTENT_TYPE = "application/vnd+spina.embed+html"
|
6
|
+
|
7
|
+
def initialize(view_context, html)
|
8
|
+
@view_context = view_context || Spina::Current.page&.view_context
|
9
|
+
@html = html
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
ActiveSupport::SafeBuffer.new(render_embeds(html))
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def embed_selector
|
19
|
+
"figure[data-trix-content-type=\"#{EMBED_CONTENT_TYPE}\"]"
|
20
|
+
end
|
21
|
+
|
22
|
+
def render_embeds(html)
|
23
|
+
doc = Nokogiri::HTML(html)
|
24
|
+
doc.css(embed_selector).each do |node|
|
25
|
+
node.replace render_embed(node.first_element_child)
|
26
|
+
end
|
27
|
+
doc.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
def render_embed(element)
|
31
|
+
embeddable = element_to_embeddable(element)
|
32
|
+
view_context.render(embeddable)
|
33
|
+
end
|
34
|
+
|
35
|
+
def element_to_embeddable(element)
|
36
|
+
embeddable = Spina::Embeds.constantize(element["data-embed-type"])
|
37
|
+
embeddable&.from_json(element["data-embed-attributes"]) || null_object
|
38
|
+
end
|
39
|
+
|
40
|
+
def null_object
|
41
|
+
{inline: ""}
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
<%= render Spina::UserInterface::ModalComponent.new(size: "max-w-screen-md h-full md:h-96") do %>
|
2
|
+
<div class="h-full" data-controller="embed" data-trix-target="<%= params[:target] %>">
|
3
|
+
<%= turbo_frame_tag :trix_attachment_html, class: 'hidden', data: {embeddables_target: "html", action: "embed-tag:embedded->embed#insertEmbeddable embed-tag:embedded->modal#close"} %>
|
4
|
+
|
5
|
+
<%= turbo_frame_tag :embeddable_form do %>
|
6
|
+
<div class="flex h-full">
|
7
|
+
<div class="p-4 w-64 bg-gray-100 md:bg-opacity-50">
|
8
|
+
<div class="text-xs font-medium text-gray-600 mb-2">
|
9
|
+
<%=t "spina.embeds.embed_a_component" %>
|
10
|
+
</div>
|
11
|
+
<% embeddables.each do |embeddable| %>
|
12
|
+
<% if embeddable.name == @embeddable.class.name %>
|
13
|
+
<% classes = "font-medium w-full text-sm px-3 py-2 rounded-lg flex items-center text-gray-900 bg-spina-dark bg-opacity-20" %>
|
14
|
+
<% else %>
|
15
|
+
<% classes = "font-medium w-full text-sm px-3 py-2 rounded-lg flex items-center text-gray-600 hover:bg-gray-200 bg-opacity-100 hover:bg-gray-200" %>
|
16
|
+
<% end %>
|
17
|
+
|
18
|
+
<%= link_to spina.new_admin_embed_path(embed_type: embeddable.name), class: classes, data: {turbo_frame: :embeddable_form} do %>
|
19
|
+
<%= heroicon(embeddable.icon, style: :solid, class: 'w-5 h-5 mr-2 text-spina-light') %>
|
20
|
+
<%= embeddable.model_name.human %>
|
21
|
+
<% end %>
|
22
|
+
<% end %>
|
23
|
+
</div>
|
24
|
+
|
25
|
+
<div class="bg-white flex-1">
|
26
|
+
<%= form_with model: @embeddable, scope: :embeddable, url: spina.admin_embeds_path, class: 'h-full' do |f| %>
|
27
|
+
<%= hidden_field_tag :embed_type, @embeddable.class.name %>
|
28
|
+
|
29
|
+
<div class="h-full relative">
|
30
|
+
<div class="flex-1 p-5 h-full pb-20 overflow-scroll">
|
31
|
+
<%= render partial: @embeddable.to_fields_path, locals: {f: f} %>
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<div class="w-full flex backdrop-filter backdrop-blur-lg absolute bottom-0 justify-end p-5 py-4 border-t border-gray-200">
|
35
|
+
<%= button_tag type: :submit, class: 'btn btn-primary' do %>
|
36
|
+
<%= heroicon('plus', style: :solid, class: 'w-6 h-6 -ml-2') %>
|
37
|
+
<%=t "spina.embeds.embed_component" %>
|
38
|
+
<% end %>
|
39
|
+
</div>
|
40
|
+
</div>
|
41
|
+
<% end %>
|
42
|
+
</div>
|
43
|
+
</div>
|
44
|
+
<% end %>
|
45
|
+
|
46
|
+
</div>
|
47
|
+
<% end %>
|
@@ -1,5 +1,5 @@
|
|
1
|
-
<div class="fixed bottom-0 left-0 w-full flex justify-center z-50">
|
1
|
+
<div class="fixed bottom-0 left-0 w-full flex justify-center z-50 pointer-events-none">
|
2
2
|
<% flash.each do |type, message| %>
|
3
3
|
<%= render Spina::UserInterface::FlashMessageComponent.new(type: type, message: message) %>
|
4
4
|
<% end %>
|
5
|
-
</div>
|
5
|
+
</div>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<div class="text-xl font-bold mb-3 text-gray-800">
|
2
|
+
Button
|
3
|
+
<div class="text-sm text-gray-500 font-normal">
|
4
|
+
A simple button that links somewhere
|
5
|
+
</div>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<%= render Spina::Forms::LabelComponent.new(f, :url) %>
|
9
|
+
<%= render Spina::Forms::TextFieldComponent.new(f, :url, autofocus: true) %>
|
10
|
+
|
11
|
+
<div class="mt-3">
|
12
|
+
<%= render Spina::Forms::LabelComponent.new(f, :label) %>
|
13
|
+
<%= render Spina::Forms::TextFieldComponent.new(f, :label) %>
|
14
|
+
</div>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<div class='border border-blue-600 text-blue-600 rounded-md flex items-center px-1 whitespace-nowrap'>
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" viewBox="0 0 20 20" fill="currentColor">
|
3
|
+
<path d="M2 6a2 2 0 012-2h6a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V6zM14.553 7.106A1 1 0 0014 8v4a1 1 0 00.553.894l2 1A1 1 0 0018 13V7a1 1 0 00-1.447-.894l-2 1z" />
|
4
|
+
</svg>
|
5
|
+
<%= vimeo.remote_title %>
|
6
|
+
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<iframe src="https://player.vimeo.com/video/<%= vimeo.id %>" width="640" height="475" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<div class="text-xl font-bold mb-3 text-gray-800">
|
2
|
+
Vimeo
|
3
|
+
<div class="text-sm text-gray-500 font-normal">
|
4
|
+
Embed a Vimeo video
|
5
|
+
</div>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<%= render Spina::Forms::LabelComponent.new(f, :url) %>
|
9
|
+
<%= render Spina::Forms::TextFieldComponent.new(f, :url, autofocus: true) %>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<div class='border border-red-600 text-red-600 rounded-md flex items-center px-1 whitespace-nowrap'>
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" viewBox="0 0 20 20" fill="currentColor">
|
3
|
+
<path d="M2 6a2 2 0 012-2h6a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V6zM14.553 7.106A1 1 0 0014 8v4a1 1 0 00.553.894l2 1A1 1 0 0018 13V7a1 1 0 00-1.447-.894l-2 1z" />
|
4
|
+
</svg>
|
5
|
+
<%= youtube.remote_title %>
|
6
|
+
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<iframe id="ytplayer" type="text/html" width="640" height="360" src="https://www.youtube.com/embed/<%= youtube.id %>" frameborder="0"></iframe>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<div class="text-xl font-bold mb-3 text-gray-800">
|
2
|
+
Youtube
|
3
|
+
<div class="text-sm text-gray-500 font-normal">
|
4
|
+
Embed a Youtube video
|
5
|
+
</div>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<%= render Spina::Forms::LabelComponent.new(f, :url) %>
|
9
|
+
<%= render Spina::Forms::TextFieldComponent.new(f, :url, autofocus: true) %>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Spina.config.importmap.draw do
|
2
2
|
# Stimulus & Turbo
|
3
3
|
pin "@hotwired/stimulus", to: "stimulus.js"
|
4
|
-
pin "@hotwired/stimulus-
|
4
|
+
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
|
5
5
|
pin "@hotwired/turbo-rails", to: "turbo.js"
|
6
6
|
|
7
7
|
# Spina entrypoint
|
data/config/locales/en.yml
CHANGED
@@ -1,4 +1,10 @@
|
|
1
1
|
en:
|
2
|
+
activemodel:
|
3
|
+
attributes:
|
4
|
+
spina/embeds/youtube:
|
5
|
+
url: youtube.com/watch?v=...
|
6
|
+
spina/embeds/vimeo:
|
7
|
+
url: vimeo.com/...
|
2
8
|
activerecord:
|
3
9
|
attributes:
|
4
10
|
spina/account:
|
@@ -94,6 +100,15 @@ en:
|
|
94
100
|
spina/user:
|
95
101
|
one: User
|
96
102
|
other: Users
|
103
|
+
helpers:
|
104
|
+
label:
|
105
|
+
spina/embeds/button:
|
106
|
+
url: URL
|
107
|
+
label: Button label
|
108
|
+
spina/embeds/youtube:
|
109
|
+
url: Youtube URL
|
110
|
+
spina/embeds/vimeo:
|
111
|
+
url: Vimeo URL
|
97
112
|
spina:
|
98
113
|
accounts:
|
99
114
|
contact_details: Contact details
|
@@ -117,6 +132,9 @@ en:
|
|
117
132
|
delete_confirmation: Are you sure you want to delete <strong>%{subject}</strong>?
|
118
133
|
edit: Edit
|
119
134
|
edit_website: Edit your website
|
135
|
+
embeds:
|
136
|
+
embed_a_component: Embed a component
|
137
|
+
embed_component: Embed component
|
120
138
|
forgot_password:
|
121
139
|
expired: Your password reset token has expired
|
122
140
|
mail_subject: Reset your password
|
data/config/routes.rb
CHANGED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Spina
|
2
|
+
module Embeddable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :embed_attributes, default: []
|
7
|
+
class_attribute :icon, default: nil
|
8
|
+
end
|
9
|
+
|
10
|
+
class_methods do
|
11
|
+
def from_json(json)
|
12
|
+
begin
|
13
|
+
attributes = JSON.parse(json)
|
14
|
+
attributes.transform_keys!(&:to_sym)
|
15
|
+
new(attributes)
|
16
|
+
rescue
|
17
|
+
Rails.logger.error "[#{self.class.name}] Couldn't parse JSON"
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def attributes(*names)
|
23
|
+
attr_accessor(*names.map(&:to_sym))
|
24
|
+
self.embed_attributes += names.map(&:to_sym)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Give it an icon
|
28
|
+
def heroicon(name)
|
29
|
+
self.icon = name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(attributes = {})
|
34
|
+
attributes.slice(*self.class.embed_attributes).each do |key, value|
|
35
|
+
instance_variable_set("@#{key}", value)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_fields_path
|
40
|
+
"#{to_partial_path}_fields"
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_trix_partial_path
|
44
|
+
to_partial_path
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Spina
|
2
|
+
module Embeds
|
3
|
+
module TrixConversion
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
# Wrap rendered partial in an <embed> tag for Trix
|
7
|
+
def to_trix_attachment(content = trix_attachment_content)
|
8
|
+
wrap_with_embed_tag(content)
|
9
|
+
end
|
10
|
+
|
11
|
+
def wrap_with_embed_tag(html)
|
12
|
+
element = html_document.create_element("spina-embed", embed_tag_attributes)
|
13
|
+
element.inner_html = html
|
14
|
+
element.to_html
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def embed_tag_attributes
|
20
|
+
spina_attributes.merge({"data-embed-attributes": embed_attributes_to_json})
|
21
|
+
end
|
22
|
+
|
23
|
+
def embed_attributes_to_json
|
24
|
+
JSON.generate Hash[self.class.embed_attributes.map{|a| [a.to_s, send(a)]}]
|
25
|
+
end
|
26
|
+
|
27
|
+
def spina_attributes
|
28
|
+
{"data-embed-type": self.class.name, "data-controller": "embed-tag"}
|
29
|
+
end
|
30
|
+
|
31
|
+
def trix_attachment_content
|
32
|
+
ApplicationController.render(partial: to_trix_partial_path, formats: :html, object: self, as: model_name.element)
|
33
|
+
end
|
34
|
+
|
35
|
+
def html_document
|
36
|
+
Nokogiri::HTML::Document.new.tap{|doc| doc.encoding = "UTF-8"}
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/spina/embeds.rb
ADDED
data/lib/spina/engine.rb
CHANGED
@@ -16,7 +16,7 @@ require 'browser'
|
|
16
16
|
module Spina
|
17
17
|
class Engine < ::Rails::Engine
|
18
18
|
isolate_namespace Spina
|
19
|
-
|
19
|
+
|
20
20
|
config.autoload_paths += %W( #{config.root}/lib )
|
21
21
|
|
22
22
|
config.to_prepare do
|
@@ -26,8 +26,9 @@ module Spina
|
|
26
26
|
require_dependency(decorator)
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
30
|
-
|
29
|
+
end
|
30
|
+
|
31
|
+
config.to_prepare do
|
31
32
|
Spina::Part.register(
|
32
33
|
Spina::Parts::Line,
|
33
34
|
Spina::Parts::MultiLine,
|
@@ -38,6 +39,7 @@ module Spina
|
|
38
39
|
Spina::Parts::Option,
|
39
40
|
Spina::Parts::Attachment
|
40
41
|
)
|
41
|
-
end
|
42
|
+
end
|
43
|
+
|
42
44
|
end
|
43
45
|
end
|
data/lib/spina/part.rb
CHANGED
@@ -8,12 +8,20 @@ module Spina
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def register(*parts)
|
11
|
-
parts.each
|
11
|
+
parts.each do |part|
|
12
|
+
unregister(part)
|
13
|
+
all << part
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def unregister(part)
|
18
|
+
all.delete_if do |registered_part|
|
19
|
+
registered_part.name == part.name
|
20
|
+
end
|
12
21
|
end
|
13
22
|
|
14
23
|
end
|
15
24
|
|
16
|
-
|
17
25
|
end
|
18
26
|
end
|
19
27
|
|
data/lib/spina/railtie.rb
CHANGED
@@ -5,6 +5,16 @@ module Spina
|
|
5
5
|
app.config.assets.precompile += %w(spina/manifest)
|
6
6
|
end
|
7
7
|
|
8
|
+
initializer "spina.theme_reloader" do |app|
|
9
|
+
reloader = ThemeReloader.new
|
10
|
+
reloader.execute
|
11
|
+
|
12
|
+
app.reloaders << reloader
|
13
|
+
app.reloader.to_run do
|
14
|
+
reloader.execute
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
8
18
|
ActiveSupport.on_load(:action_controller) do
|
9
19
|
::ActionController::Base.send(:include, Spina::AdminSectionable)
|
10
20
|
end
|
data/lib/spina/theme.rb
CHANGED
@@ -1,13 +1,18 @@
|
|
1
1
|
module Spina
|
2
2
|
class Theme
|
3
3
|
|
4
|
-
attr_accessor :name, :title, :parts, :page_parts, :structures, :view_templates, :layout_parts, :custom_pages, :plugins, :public_theme, :config, :navigations, :resources
|
4
|
+
attr_accessor :name, :title, :parts, :page_parts, :structures, :view_templates, :layout_parts, :custom_pages, :plugins, :public_theme, :config, :navigations, :resources, :embeds
|
5
5
|
|
6
6
|
class << self
|
7
7
|
|
8
8
|
def all
|
9
9
|
::Spina::THEMES
|
10
10
|
end
|
11
|
+
|
12
|
+
def unregister(name)
|
13
|
+
theme = find_by_name(name)
|
14
|
+
all.delete(theme) if theme
|
15
|
+
end
|
11
16
|
|
12
17
|
def find_by_name(name)
|
13
18
|
all.find { |theme| theme.name == name }
|
@@ -17,6 +22,7 @@ module Spina
|
|
17
22
|
theme = ::Spina::Theme.new
|
18
23
|
yield theme
|
19
24
|
raise 'Missing theme name' if theme.name.nil?
|
25
|
+
unregister(theme.name)
|
20
26
|
if theme.plugins.nil?
|
21
27
|
theme.plugins = ::Spina::Plugin.all.map { |plugin| plugin.name }
|
22
28
|
end
|
@@ -33,8 +39,13 @@ module Spina
|
|
33
39
|
@custom_pages = []
|
34
40
|
@navigations = []
|
35
41
|
@resources = []
|
42
|
+
@embeds = []
|
36
43
|
@public_theme = false
|
37
44
|
end
|
45
|
+
|
46
|
+
def embeddables
|
47
|
+
embeds.map{|embed| Embeds.constantize(embed)}
|
48
|
+
end
|
38
49
|
|
39
50
|
def new_page_templates(resource: nil)
|
40
51
|
page_collection = resource&.name || "main"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Spina::ThemeReloader
|
2
|
+
delegate :execute_if_updated, :execute, :updated?, to: :updater
|
3
|
+
|
4
|
+
def reload!
|
5
|
+
theme_paths.each { |path| load path }
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def updater
|
11
|
+
@updater ||= Rails.application.config.file_watcher.new(theme_paths) do
|
12
|
+
reload!
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def theme_paths
|
17
|
+
Rails.root.glob("config/initializers/themes/*.rb")
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/lib/spina/version.rb
CHANGED
data/lib/spina.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'spina/engine'
|
2
2
|
require 'spina/admin_sectionable'
|
3
3
|
require 'spina/railtie'
|
4
|
+
require 'spina/theme_reloader'
|
4
5
|
require 'spina/plugin'
|
5
6
|
require 'spina/theme'
|
6
7
|
require 'spina/tailwind_purger'
|
@@ -8,6 +9,9 @@ require 'spina/attr_json_spina_parts_model'
|
|
8
9
|
require 'spina/attr_json_monkeypatch'
|
9
10
|
require 'spina/authentication/sessions'
|
10
11
|
require 'spina/authentication/basic'
|
12
|
+
require 'spina/embeddable'
|
13
|
+
require 'spina/embeds'
|
14
|
+
require 'spina/embeds/trix_conversion'
|
11
15
|
|
12
16
|
module Spina
|
13
17
|
include ActiveSupport::Configurable
|
data/lib/tasks/spina_tasks.rake
CHANGED
@@ -25,7 +25,7 @@ namespace :spina do
|
|
25
25
|
desc "Compile Tailwind.css for Spina"
|
26
26
|
task :compile do
|
27
27
|
Dir.chdir(File.join(__dir__, "../..")) do
|
28
|
-
system "npx tailwindcss
|
28
|
+
system "npx tailwindcss@latest build -i ./app/assets/stylesheets/spina/tailwind/custom.css -o ./app/assets/stylesheets/spina/_tailwind.css -c ./app/assets/config/spina/tailwind.config.js"
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spina
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bram Jetten
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -182,50 +182,44 @@ dependencies:
|
|
182
182
|
name: importmap-rails
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
184
184
|
requirements:
|
185
|
-
- -
|
185
|
+
- - ">="
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version: 0.
|
187
|
+
version: 0.7.6
|
188
188
|
type: :runtime
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
|
-
- -
|
192
|
+
- - ">="
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version: 0.
|
194
|
+
version: 0.7.6
|
195
195
|
- !ruby/object:Gem::Dependency
|
196
196
|
name: turbo-rails
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|
198
198
|
requirements:
|
199
|
-
- - "
|
199
|
+
- - ">="
|
200
200
|
- !ruby/object:Gem::Version
|
201
|
-
version: 0.
|
201
|
+
version: 0.8.0
|
202
202
|
type: :runtime
|
203
203
|
prerelease: false
|
204
204
|
version_requirements: !ruby/object:Gem::Requirement
|
205
205
|
requirements:
|
206
|
-
- - "
|
206
|
+
- - ">="
|
207
207
|
- !ruby/object:Gem::Version
|
208
|
-
version: 0.
|
208
|
+
version: 0.8.0
|
209
209
|
- !ruby/object:Gem::Dependency
|
210
210
|
name: stimulus-rails
|
211
211
|
requirement: !ruby/object:Gem::Requirement
|
212
212
|
requirements:
|
213
213
|
- - ">="
|
214
214
|
- !ruby/object:Gem::Version
|
215
|
-
version: 0.
|
216
|
-
- - "<"
|
217
|
-
- !ruby/object:Gem::Version
|
218
|
-
version: 0.5.0
|
215
|
+
version: 0.7.0
|
219
216
|
type: :runtime
|
220
217
|
prerelease: false
|
221
218
|
version_requirements: !ruby/object:Gem::Requirement
|
222
219
|
requirements:
|
223
220
|
- - ">="
|
224
221
|
- !ruby/object:Gem::Version
|
225
|
-
version: 0.
|
226
|
-
- - "<"
|
227
|
-
- !ruby/object:Gem::Version
|
228
|
-
version: 0.5.0
|
222
|
+
version: 0.7.0
|
229
223
|
- !ruby/object:Gem::Dependency
|
230
224
|
name: babosa
|
231
225
|
requirement: !ruby/object:Gem::Requirement
|
@@ -821,17 +815,21 @@ files:
|
|
821
815
|
- app/assets/images/spina/spina.png
|
822
816
|
- app/assets/images/spina/spina.svg
|
823
817
|
- app/assets/javascripts/spina/application.js
|
818
|
+
- app/assets/javascripts/spina/controllers/application.js
|
824
819
|
- app/assets/javascripts/spina/controllers/attachment_picker_controller.js
|
825
820
|
- app/assets/javascripts/spina/controllers/autofocus_controller.js
|
826
821
|
- app/assets/javascripts/spina/controllers/button_controller.js
|
827
822
|
- app/assets/javascripts/spina/controllers/confetti_controller.js
|
828
823
|
- app/assets/javascripts/spina/controllers/confirm_controller.js
|
829
824
|
- app/assets/javascripts/spina/controllers/delegate_click_controller.js
|
825
|
+
- app/assets/javascripts/spina/controllers/embed_controller.js
|
826
|
+
- app/assets/javascripts/spina/controllers/embed_tag_controller.js
|
830
827
|
- app/assets/javascripts/spina/controllers/exists_controller.js
|
831
828
|
- app/assets/javascripts/spina/controllers/form_controller.js
|
832
829
|
- app/assets/javascripts/spina/controllers/hotkeys_controller.js
|
833
830
|
- app/assets/javascripts/spina/controllers/image_collection_controller.js
|
834
831
|
- app/assets/javascripts/spina/controllers/image_fade_in_controller.js
|
832
|
+
- app/assets/javascripts/spina/controllers/index.js
|
835
833
|
- app/assets/javascripts/spina/controllers/infinite_scroll_controller.js
|
836
834
|
- app/assets/javascripts/spina/controllers/loading_button_controller.js
|
837
835
|
- app/assets/javascripts/spina/controllers/media_picker_controller.js
|
@@ -922,6 +920,7 @@ files:
|
|
922
920
|
- app/controllers/spina/admin/accounts_controller.rb
|
923
921
|
- app/controllers/spina/admin/admin_controller.rb
|
924
922
|
- app/controllers/spina/admin/attachments_controller.rb
|
923
|
+
- app/controllers/spina/admin/embeds_controller.rb
|
925
924
|
- app/controllers/spina/admin/images_controller.rb
|
926
925
|
- app/controllers/spina/admin/layout_controller.rb
|
927
926
|
- app/controllers/spina/admin/media_folders_controller.rb
|
@@ -963,6 +962,10 @@ files:
|
|
963
962
|
- app/models/spina/application_record.rb
|
964
963
|
- app/models/spina/attachment.rb
|
965
964
|
- app/models/spina/current.rb
|
965
|
+
- app/models/spina/embeds/base.rb
|
966
|
+
- app/models/spina/embeds/button.rb
|
967
|
+
- app/models/spina/embeds/vimeo.rb
|
968
|
+
- app/models/spina/embeds/youtube.rb
|
966
969
|
- app/models/spina/image.rb
|
967
970
|
- app/models/spina/media_folder.rb
|
968
971
|
- app/models/spina/navigation.rb
|
@@ -985,6 +988,7 @@ files:
|
|
985
988
|
- app/models/spina/user.rb
|
986
989
|
- app/presenters/spina/content_presenter.rb
|
987
990
|
- app/presenters/spina/menu_presenter.rb
|
991
|
+
- app/presenters/spina/rich_text_presenter.rb
|
988
992
|
- app/serializers/spina/api/base_serializer.rb
|
989
993
|
- app/serializers/spina/api/image_serializer.rb
|
990
994
|
- app/serializers/spina/api/navigation_serializer.rb
|
@@ -999,6 +1003,7 @@ files:
|
|
999
1003
|
- app/views/spina/admin/attachments/edit.html.erb
|
1000
1004
|
- app/views/spina/admin/attachments/index.html.erb
|
1001
1005
|
- app/views/spina/admin/attachments/show.html.erb
|
1006
|
+
- app/views/spina/admin/embeds/new.html.erb
|
1002
1007
|
- app/views/spina/admin/images/_image.html.erb
|
1003
1008
|
- app/views/spina/admin/images/edit.html.erb
|
1004
1009
|
- app/views/spina/admin/images/index.html.erb
|
@@ -1057,6 +1062,15 @@ files:
|
|
1057
1062
|
- app/views/spina/admin/users/edit.html.erb
|
1058
1063
|
- app/views/spina/admin/users/index.html.erb
|
1059
1064
|
- app/views/spina/admin/users/new.html.erb
|
1065
|
+
- app/views/spina/embeds/buttons/_button.html.erb
|
1066
|
+
- app/views/spina/embeds/buttons/_button_fields.html.erb
|
1067
|
+
- app/views/spina/embeds/buttons/_trix_button.html.erb
|
1068
|
+
- app/views/spina/embeds/vimeos/_thumbnail.html.erb
|
1069
|
+
- app/views/spina/embeds/vimeos/_vimeo.html.erb
|
1070
|
+
- app/views/spina/embeds/vimeos/_vimeo_fields.html.erb
|
1071
|
+
- app/views/spina/embeds/youtubes/_thumbnail.html.erb
|
1072
|
+
- app/views/spina/embeds/youtubes/_youtube.html.erb
|
1073
|
+
- app/views/spina/embeds/youtubes/_youtube_fields.html.erb
|
1060
1074
|
- app/views/spina/sitemaps/show.xml.builder
|
1061
1075
|
- app/views/spina/user_mailer/forgot_password.html.erb
|
1062
1076
|
- app/views/spina/user_mailer/forgot_password.text.erb
|
@@ -1115,12 +1129,16 @@ files:
|
|
1115
1129
|
- lib/spina/attr_json_spina_parts_model.rb
|
1116
1130
|
- lib/spina/authentication/basic.rb
|
1117
1131
|
- lib/spina/authentication/sessions.rb
|
1132
|
+
- lib/spina/embeddable.rb
|
1133
|
+
- lib/spina/embeds.rb
|
1134
|
+
- lib/spina/embeds/trix_conversion.rb
|
1118
1135
|
- lib/spina/engine.rb
|
1119
1136
|
- lib/spina/part.rb
|
1120
1137
|
- lib/spina/plugin.rb
|
1121
1138
|
- lib/spina/railtie.rb
|
1122
1139
|
- lib/spina/tailwind_purger.rb
|
1123
1140
|
- lib/spina/theme.rb
|
1141
|
+
- lib/spina/theme_reloader.rb
|
1124
1142
|
- lib/spina/version.rb
|
1125
1143
|
- lib/tasks/spina_tasks.rake
|
1126
1144
|
homepage: https://www.spinacms.com
|