spina 2.19.0 → 2.21.0

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.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +0 -2
  3. data/app/assets/builds/spina/tailwind.css +3338 -3725
  4. data/app/assets/config/spina/manifest.js +2 -2
  5. data/app/assets/javascripts/spina/application.js +1 -1
  6. data/app/assets/javascripts/spina/controllers/confetti_controller.js +1 -1
  7. data/app/assets/javascripts/spina/controllers/confirm_controller.js +2 -2
  8. data/app/assets/javascripts/spina/controllers/data_binding_controller.js +234 -1
  9. data/app/assets/javascripts/spina/controllers/form_controller.js +1 -2
  10. data/app/assets/javascripts/spina/controllers/hotkeys_controller.js +1 -1
  11. data/app/assets/javascripts/spina/controllers/navigation_controller.js +4 -4
  12. data/app/assets/javascripts/spina/controllers/reveal_controller.js +424 -1
  13. data/app/assets/javascripts/spina/controllers/sortable_controller.js +1 -2
  14. data/app/assets/javascripts/spina/libraries/canvas-confetti.js +1 -1
  15. data/app/assets/javascripts/spina/libraries/hotkeys.js +1 -1
  16. data/app/assets/javascripts/spina/libraries/sortablejs.js +1 -1
  17. data/app/assets/javascripts/spina/libraries/trix.js +1 -1
  18. data/app/assets/stylesheets/spina/application.tailwind.css +105 -62
  19. data/app/assets/stylesheets/spina/fonts-propshaft.css +114 -0
  20. data/app/components/spina/forms/switch_component.html.erb +2 -2
  21. data/app/components/spina/forms/trix_toolbar_component.html.erb +16 -33
  22. data/app/components/spina/media_picker/modal_component.html.erb +1 -1
  23. data/app/components/spina/media_picker/modal_component.rb +2 -2
  24. data/app/components/spina/pages/actions_component.html.erb +4 -4
  25. data/app/components/spina/pages/location_component.html.erb +2 -2
  26. data/app/components/spina/pages/new_page_button_component.html.erb +2 -2
  27. data/app/components/spina/pages/page_component.html.erb +1 -1
  28. data/app/components/spina/pages/page_component.rb +2 -2
  29. data/app/components/spina/pages/translations_component.html.erb +3 -3
  30. data/app/components/spina/pages/translations_component.rb +1 -1
  31. data/app/components/spina/user_interface/modal_component.html.erb +2 -2
  32. data/app/components/spina/user_interface/tab_link_component.rb +1 -1
  33. data/app/components/spina/user_interface/translations_component.html.erb +2 -2
  34. data/app/components/spina/user_interface/translations_component.rb +1 -1
  35. data/app/controllers/concerns/spina/current_spina_account.rb +1 -1
  36. data/app/controllers/spina/admin/page_select_options_controller.rb +1 -1
  37. data/app/controllers/spina/admin/resource_select_options_controller.rb +1 -1
  38. data/app/controllers/spina/application_controller.rb +1 -1
  39. data/app/helpers/spina/admin/pages_helper.rb +23 -4
  40. data/app/jobs/spina/replace_signed_id_job.rb +12 -9
  41. data/app/models/concerns/spina/attachable.rb +1 -1
  42. data/app/models/concerns/spina/translated_content.rb +1 -1
  43. data/app/models/spina/account.rb +2 -2
  44. data/app/models/spina/embeds/youtube.rb +1 -1
  45. data/app/models/spina/resource.rb +3 -1
  46. data/app/models/spina/setting.rb +2 -0
  47. data/app/presenters/spina/menu_presenter.rb +7 -12
  48. data/app/views/layouts/spina/admin/application.html.erb +9 -2
  49. data/app/views/spina/admin/embeds/new.html.erb +4 -4
  50. data/app/views/spina/admin/images/_image.html.erb +1 -1
  51. data/app/views/spina/admin/layout/edit.html.erb +2 -2
  52. data/app/views/spina/admin/move_pages/new.html.erb +2 -2
  53. data/app/views/spina/admin/navigation_items/_navigation_item.html.erb +5 -5
  54. data/app/views/spina/admin/pages/_form.html.erb +1 -1
  55. data/app/views/spina/admin/pages/_form_advanced.html.erb +1 -1
  56. data/app/views/spina/admin/pages/edit_template.html.erb +2 -2
  57. data/app/views/spina/admin/pages/index.html.erb +1 -1
  58. data/app/views/spina/admin/parts/image_collections/_fields.html.erb +1 -1
  59. data/app/views/spina/admin/parts/images/_form.html.erb +1 -1
  60. data/app/views/spina/admin/parts/page_links/_form.html.erb +2 -2
  61. data/app/views/spina/admin/parts/repeaters/_form.html.erb +1 -1
  62. data/app/views/spina/admin/parts/resource_links/_form.html.erb +1 -1
  63. data/app/views/spina/admin/parts/texts/_form.html.erb +2 -2
  64. data/app/views/spina/admin/settings/_wysiwyg_field.html.erb +3 -3
  65. data/app/views/spina/admin/shared/_navigation.html.erb +1 -1
  66. data/app/views/spina/admin/users/index.html.erb +2 -2
  67. data/app/views/spina/sitemaps/show.xml.builder +1 -1
  68. data/config/locales/de.yml +2 -0
  69. data/config/routes.rb +2 -2
  70. data/db/migrate/13_add_json_attributes_to_spina_accounts.rb +1 -1
  71. data/db/migrate/14_add_json_attributes_to_spina_pages.rb +1 -1
  72. data/db/migrate/15_add_slug_to_spina_resources.rb +1 -1
  73. data/db/migrate/18_change_default_spina_resources_slug.rb +9 -0
  74. data/db/migrate/7_create_spina_settings.rb +1 -1
  75. data/lib/generators/spina/tailwind_config_generator.rb +1 -1
  76. data/lib/generators/spina/templates/app/assets/stylesheets/spina/application.tailwind.css.tt +232 -0
  77. data/lib/generators/spina/templates/app/views/demo/shared/_languages.html.erb +2 -2
  78. data/lib/spina/engine.rb +1 -2
  79. data/lib/spina/railtie.rb +4 -1
  80. data/lib/spina/version.rb +1 -1
  81. data/lib/spina.rb +63 -83
  82. data/lib/tasks/install.rake +1 -1
  83. data/lib/tasks/tailwind.rake +2 -3
  84. metadata +17 -49
  85. data/app/assets/javascripts/spina/libraries/form-request-submit-polyfill.js +0 -1
  86. data/app/assets/javascripts/spina/libraries/form-request-submit-polyfill@2.0.0.js +0 -27
  87. data/app/assets/javascripts/spina/libraries/stimulus-data-bindings@1.3.2.js +0 -234
  88. data/app/assets/javascripts/spina/libraries/stimulus-reveal@1.4.2.js +0 -424
  89. data/lib/generators/spina/templates/app/assets/config/spina/tailwind.config.js.tt +0 -23
  90. /data/app/assets/stylesheets/spina/{fonts.css.erb → fonts-sprockets.css.erb} +0 -0
@@ -1,27 +0,0 @@
1
- (function(prototype) {
2
- if (typeof prototype.requestSubmit == "function")
3
- return;
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
- function validateSubmitter(submitter, form) {
18
- submitter instanceof HTMLElement || raise(TypeError, "parameter 1 is not of type 'HTMLElement'");
19
- submitter.type == "submit" || raise(TypeError, "The specified element is not a submit button");
20
- submitter.form == form || raise(DOMException, "The specified element is not owned by this form element", "NotFoundError");
21
- }
22
- function raise(errorConstructor, message, name) {
23
- throw new errorConstructor("Failed to execute 'requestSubmit' on 'HTMLFormElement': " + message + ".", name);
24
- }
25
- })(HTMLFormElement.prototype);
26
- export default null;
27
-
@@ -1,234 +0,0 @@
1
- import { Controller } from '@hotwired/stimulus'
2
-
3
- /**
4
- * One way data and visibility bindings for inputs
5
- * @extends Controller
6
- */
7
- export default class DataBindingController extends Controller {
8
- /**
9
- * Initialize bindings on connection to the DOM
10
- */
11
- connect() {
12
- if (this.element.dataset.bindingDebug === "true") {
13
- this.debugMode = true
14
- }
15
-
16
- this._debug("stimulus-data-binding: connecting to wrapper:", this.element)
17
-
18
- const sourceElements = Array.from(this.element.querySelectorAll('[data-binding-target]'))
19
- if (this.element.dataset.bindingTarget) sourceElements.unshift(this.element)
20
-
21
- if (sourceElements.length === 0) this._debug("No source elements found. Did you set data-binding-target on your source elements?")
22
-
23
- for (const sourceElement of sourceElements) {
24
- if (this.debugMode) console.group("stimulus-data-binding: Source element")
25
- this._debug("Source element found", sourceElement)
26
-
27
- if (sourceElement.dataset.bindingInitial !== 'false') {
28
- this._debug("Running initial binding on source element")
29
- this._runBindings(sourceElement)
30
- } else {
31
- this._debug("%cNot running initial binding on source element as binding-initial is set to false", "color: rgba(150,150,150,0.8);")
32
- }
33
-
34
- if (this.debugMode) console.groupEnd()
35
- }
36
- }
37
-
38
- /**
39
- * Updates bindings for the current element.
40
- * @param {Event} e - an event with a currentTarget DOMElement
41
- */
42
- update(e) {
43
- this._runBindings(e.currentTarget)
44
- }
45
-
46
- /**
47
- * @private
48
- * @param {DOMElement} source
49
- */
50
- _runBindings(source) {
51
- this._debug("Searching for targets for source: ", source)
52
- for (const targetRef of source.dataset.bindingTarget.split(' ')) {
53
- const targetElements = this._bindingElements(targetRef)
54
-
55
- if (targetElements.length === 0) this._debug(`Could not find any target elements for ref ${targetRef}. Have you set data-target-ref="${targetRef}" on your target elements?`)
56
-
57
- for (const target of targetElements) {
58
- if (this.debugMode) console.group("stimulus-data-binding: Target Element")
59
- this._debug("Target found. Running bindings for target: ", target)
60
-
61
- const bindingCondition = this._getDatum('bindingCondition', source, target)
62
-
63
- if (bindingCondition) {
64
- this._debug(`Evaluating binding condition: '${bindingCondition}'`)
65
- } else {
66
- this._debug(`%cNo binding condition set. Evaluating as true. To add a condition set 'data-binding-condition="..."'`, "color: rgba(150,150,150,0.8);")
67
- }
68
-
69
- const conditionPassed = this._evaluate(
70
- bindingCondition,
71
- {
72
- source,
73
- target
74
- }
75
- )
76
-
77
- if (conditionPassed) {
78
- this._debug(`Condition evaluated to: `, conditionPassed)
79
- } else {
80
- this._debug(`Condition evaluated to: `, conditionPassed)
81
- }
82
-
83
- const bindingValue = this._getDatum('bindingValue', source, target)
84
-
85
- if (bindingValue) {
86
- this._debug(`Evaluating binding value: '${bindingValue}'`)
87
- } else {
88
- this._debug(`%cNo binding value set, evaluating as true. to set a value for the attribute / property on your target elements set 'data-binding-value="..."'`, "color: rgba(150,150,150,0.8);")
89
- }
90
-
91
- const value = this._evaluate(
92
- bindingValue,
93
- {
94
- source,
95
- target
96
- }
97
- )
98
-
99
- this._debug(`Value evaluated to: '${value}'`)
100
-
101
- const bindingAttribute = this._getDatum(
102
- 'bindingAttribute',
103
- source,
104
- target
105
- )
106
-
107
- if (!bindingAttribute) {
108
- this._debug(`%cNo binding attribute set. To add attributes to your target element set 'data-binding-attribute="..."'`, "color: rgba(150,150,150,0.8);")
109
- }
110
-
111
- if (bindingAttribute) {
112
- for (const attribute of bindingAttribute.split(' ')) {
113
- if (conditionPassed) {
114
- this._debug(`Condition passed so setting attribute '${attribute}' to '${value}'`)
115
- target.setAttribute(attribute, value)
116
- } else {
117
- this._debug(`Condition failed so removing attribute '${attribute}'`)
118
- target.removeAttribute(attribute)
119
- }
120
- }
121
- }
122
-
123
- const bindingProperty = this._getDatum(
124
- 'bindingProperty',
125
- source,
126
- target
127
- )
128
-
129
- if (!bindingProperty) {
130
- this._debug(`%cNo binding property set. To add properties to your target element set 'data-binding-property="..."'`, "color: rgba(150,150,150,0.8);")
131
- }
132
-
133
- if (bindingProperty) {
134
- for (const prop of bindingProperty.split(' ')) {
135
- const propertyValue = conditionPassed ? value : ''
136
- if (target[prop] != propertyValue) { target.dataset.hasChanged = true }
137
-
138
- if (conditionPassed) {
139
- this._debug(`Condition passed so setting property '${prop}' from ${target[prop]} to '${value}'`)
140
- } else {
141
- this._debug(`Condition failed so setting property '${prop}' from ${target[prop]} to '' (empty string)`)
142
- }
143
-
144
- target[prop] = propertyValue
145
- }
146
- }
147
-
148
- const bindingClass = this._getDatum(
149
- 'bindingClass',
150
- source,
151
- target
152
- )
153
-
154
- if (!bindingClass) {
155
- this._debug(`%cNo binding class set. To add classes to your target element set 'data-binding-class="..."'`, "color: rgba(150,150,150,0.8);")
156
- }
157
-
158
- if (bindingClass) {
159
- for (const klass of bindingClass.split(' ')) {
160
- if (conditionPassed) {
161
- this._debug(`Condition passed so adding class '${klass}'`)
162
- target.classList.add(klass)
163
- } else {
164
- this._debug(`Condition failed so removing class '${klass}'`)
165
- target.classList.remove(klass)
166
- }
167
- }
168
- }
169
-
170
- const bindingEvent = this._getDatum('bindingEvent', source, target)
171
-
172
- if (!bindingEvent) {
173
- this._debug(`%cNo binding event set. To dispatch events on property change to your target element set 'data-binding-event="..."'`, "color: rgba(150,150,150,0.8);")
174
- }
175
-
176
- if (bindingEvent) {
177
- for (const event of bindingEvent.split(' ')) {
178
- if (target.dataset.hasChanged) {
179
- this._debug(`Target has changed so dispatching event ${event}`)
180
- target.dispatchEvent(new Event(event, { cancelable: true, bubbles: true }))
181
- delete target.dataset.hasChanged
182
- } else {
183
- this._debug(`No changes to target properties so not dispatching '${event}'`)
184
- }
185
- }
186
- }
187
-
188
- if (this.debugMode) console.groupEnd()
189
- }
190
- }
191
- }
192
-
193
- /**
194
- * @private
195
- * @param {String} name - the name of the binding reference
196
- */
197
- _bindingElements(name) {
198
- return this.element.querySelectorAll(`[data-binding-ref="${name}"]`)
199
- }
200
-
201
- /**
202
- * @private
203
- * @param {String} attribute - the attribute to fetch from the source / target dataaset
204
- * @param {String} source - The source element to get the attribute from, only loads if target doesnt have it
205
- * @param {String} target - The target element to get the attribute from, has precedence over the source
206
- */
207
- _getDatum(attribute, source, target) {
208
- return target.dataset[attribute] || source.dataset[attribute]
209
- }
210
-
211
- /**
212
- * @private
213
- * @param {String} expression - expression to safe eval
214
- * @param {Object} variables - variables to be present when evaluating the given expression
215
- */
216
- _evaluate(expression, variables = {}) {
217
- if (!expression) return true
218
- return new Function(
219
- Object.keys(variables).map((v) => `$${v}`),
220
- `return ${expression.trim()}`
221
- )(...Object.values(variables))
222
- }
223
-
224
- /**
225
- * @private
226
- * @param {String} expression - expression to safe eval
227
- * @param {Object} variables - variables to be present when evaluating the given expression
228
- */
229
- _debug(...args) {
230
- if (this.debugMode) {
231
- console.log(...args)
232
- }
233
- }
234
- }
@@ -1,424 +0,0 @@
1
- import { Controller } from "@hotwired/stimulus";
2
-
3
- /**
4
- * Stimulus controller to toggle element visibility
5
- * @extends Controller
6
- */
7
- export default class RevealController extends Controller {
8
- static values = {
9
- open: Boolean,
10
- transitioning: Boolean,
11
- targetSelector: String,
12
- toggleKeys: String,
13
- showKeys: String,
14
- hideKeys: String,
15
- away: Boolean,
16
- debug: Boolean,
17
- };
18
-
19
- connect() {
20
- this._initCloseKeypressListener();
21
- this._initToggleKeypressListener();
22
- this._initShowKeypressListener();
23
- this._awayHandler = this._awayHandler.bind(this);
24
- }
25
-
26
- disconnect() {
27
- this._teardown();
28
- }
29
-
30
- /**
31
- * Shows elements connected to the controller.
32
- * @param {Event} event - an event with a currentTarget DOMElement
33
- */
34
- show(event) {
35
- if (this.openValue || this.transitioningValue) return;
36
-
37
- this._init(event, true);
38
- }
39
-
40
- /**
41
- * Hides elements connected to the controller.
42
- * @param {Event} event - an event with a currentTarget DOMElement
43
- */
44
- hide(event) {
45
- if (!this.openValue || this.transitioningValue) return;
46
-
47
- this._init(event, false);
48
- }
49
-
50
- /**
51
- * Toggles elements connected to the controller.
52
- * @param {Event} event - an event with a currentTarget DOMElement
53
- */
54
- toggle(event) {
55
- if (this.transitioningValue) return;
56
-
57
- this._init(event, !this.openValue);
58
- }
59
-
60
- /**
61
- * Stops event propagation of elements connected to the controller.
62
- * @param {Event} event - an event with a currentTarget DOMElement
63
- */
64
- stop(event) {
65
- event.stopPropagation();
66
- }
67
-
68
- // Private methods
69
-
70
- /**
71
- * @private
72
- * @param {Event} event
73
- * @param {Event} shouldOpen
74
- */
75
- async _init(event, shouldOpen) {
76
- if (event && event.currentTarget && event.currentTarget.dataset) {
77
- if ("revealPreventDefault" in event.currentTarget.dataset) {
78
- event.preventDefault();
79
- }
80
- if ("revealStopPropagation" in event.currentTarget.dataset) {
81
- event.stopPropagation();
82
- }
83
- }
84
- // start stuff
85
- const startSelector = `${this.selector}[data-${shouldOpen ? "enter" : "leave"
86
- }-start]`;
87
- const startPromises = this._didInitWithPromise(startSelector, shouldOpen);
88
- await Promise.all(startPromises);
89
-
90
- const defaultSelector = `${this.selector}:not([data-${shouldOpen ? "enter" : "leave"
91
- }-start]):not([data-${shouldOpen ? "enter" : "leave"}-end])`;
92
- const defaultPromises = this._didInitWithPromise(
93
- defaultSelector,
94
- shouldOpen
95
- );
96
- await Promise.all(defaultPromises);
97
-
98
- // end stuff
99
- const endSelector = `${this.selector}[data-${shouldOpen ? "enter" : "leave"
100
- }-end]`;
101
- const endPromises = this._didInitWithPromise(endSelector, shouldOpen);
102
- await Promise.all(endPromises);
103
- }
104
-
105
- /**
106
- * @private
107
- */
108
- _teardown() {
109
- if (this.hasAwayValue) {
110
- document.removeEventListener("click", this._awayHandler);
111
- }
112
- }
113
-
114
- _didInitWithPromise(selector, shouldOpen) {
115
- this._debug("selecting", selector, this._fetchElements(selector));
116
- return this._fetchElements(selector).map((element) => {
117
- return this._doInitTransition(element, shouldOpen);
118
- });
119
- }
120
-
121
- /**
122
- * @private
123
- */
124
- _initCloseKeypressListener() {
125
- if (this.hasHideKeysValue) {
126
- document.addEventListener("keydown", (event) => {
127
- if (!this.openValue) return;
128
- if (!this.hideKeysValue.split(",").includes(event.key.toLowerCase())) {
129
- return;
130
- }
131
-
132
- event.stopPropagation();
133
- this.toggle(event);
134
- });
135
- }
136
- }
137
-
138
- /**
139
- * @private
140
- */
141
- _initToggleKeypressListener() {
142
- if (this.hasToggleKeysValue) {
143
- document.addEventListener("keydown", (event) => {
144
- if (
145
- !this.toggleKeysValue.split(",").includes(event.key.toLowerCase())
146
- ) {
147
- return;
148
- }
149
-
150
- event.stopPropagation();
151
-
152
- this.toggle(event);
153
- });
154
- }
155
- }
156
-
157
- /**
158
- * @private
159
- */
160
- _initShowKeypressListener() {
161
- if (this.hasShowKeysValue) {
162
- document.addEventListener("keydown", (event) => {
163
- if (this.openValue) return;
164
- if (!this.showKeysValue.split(",").includes(event.key.toLowerCase())) {
165
- return;
166
- }
167
-
168
- event.stopPropagation();
169
-
170
- this.toggle(event);
171
- });
172
- }
173
- }
174
-
175
- /**
176
- * @private
177
- */
178
- _awayHandler(event) {
179
- if (!this.element.contains(event.target)) {
180
- document.removeEventListener("click", this._awayHandler);
181
- this.hide(event);
182
- }
183
- return true;
184
- }
185
-
186
- /**
187
- * @private
188
- * @param {DOMElement} target
189
- * @param {boolean} openState
190
- */
191
- _doInitTransition(target, openState) {
192
- this._debug("init transition", `${openState ? "open" : "closed"}`, target);
193
- this._debug(
194
- "dispatching event",
195
- `reveal:${openState ? "show" : "hide"}`,
196
- target
197
- );
198
- target.dispatchEvent(
199
- new Event(`reveal:${openState ? "show" : "hide"}`, {
200
- bubbles: true,
201
- cancelable: false,
202
- })
203
- );
204
-
205
- return new Promise((resolve, reject) => {
206
- if (
207
- "transition" in target.dataset &&
208
- this.element.offsetParent !== null
209
- ) {
210
- requestAnimationFrame(() => {
211
- this._transitionSetup(target, openState);
212
- const _didEndTransition = this._didEndTransition.bind(this);
213
-
214
- target.addEventListener(
215
- "transitionend",
216
- function _didEndTransitionHandler() {
217
- _didEndTransition(target, openState);
218
- target.removeEventListener(
219
- "transitionend",
220
- _didEndTransitionHandler
221
- );
222
- resolve();
223
- }
224
- );
225
-
226
- requestAnimationFrame(() => {
227
- this._doStartTransition(target, openState);
228
- });
229
- });
230
- } else {
231
- if (openState) {
232
- this._debug(
233
- "force hidden - init",
234
- `${openState ? "open" : "closed"}`,
235
- target
236
- );
237
- target.hidden = !target.hidden;
238
- }
239
- this._doCompleteTransition(target, openState);
240
- resolve();
241
- }
242
- });
243
- }
244
-
245
- /**
246
- * @private
247
- * @param {DOMElement} target
248
- */
249
- _doStartTransition(target, openState) {
250
- this._debug("start transition", `${openState ? "open" : "closed"}`, target);
251
- this.transitioningValue = true;
252
- if (target.dataset.useTransitionClasses === "true") {
253
- const transitionClasses = this._transitionClasses(
254
- target,
255
- this.transitionType
256
- );
257
- target.classList.add(...transitionClasses.end.split(" "));
258
- target.classList.remove(...transitionClasses.start.split(" "));
259
- } else {
260
- const transitions = this._transitionDefaults(openState);
261
- target.style.transformOrigin = transitions.origin;
262
- target.style.transitionProperty = "opacity transform";
263
- target.style.transitionDuration = `${transitions.duration / 1000}s`;
264
- target.style.transitionTimingFunction = "cubic-bezier(0.4, 0.0, 0.2, 1)";
265
-
266
- target.style.opacity = transitions.to.opacity;
267
- target.style.transform = `scale(${transitions.to.scale / 100})`;
268
- }
269
- }
270
-
271
- /**
272
- * @private
273
- * @param {DOMElement} target
274
- * @param {boolean} openState
275
- */
276
- _didEndTransition(target, openState) {
277
- this._debug("end transition", `${openState ? "open" : "closed"}`, target);
278
- if (target.dataset.useTransitionClasses === "true") {
279
- const transitionClasses = this._transitionClasses(
280
- target,
281
- this.transitionType
282
- );
283
- target.classList.remove(...transitionClasses.before.split(" "));
284
- } else {
285
- target.style.opacity = target.dataset.opacityCache;
286
- target.style.transform = target.dataset.transformCache;
287
- target.style.transformOrigin = target.dataset.transformOriginCache;
288
- }
289
- this._doCompleteTransition(target, openState);
290
- }
291
-
292
- /**
293
- * @private
294
- * @param {DOMElement} target
295
- * @param {boolean} openState
296
- */
297
- _doCompleteTransition(target, openState) {
298
- this._debug(
299
- "complete transition",
300
- `${openState ? "open" : "closed"}`,
301
- target
302
- );
303
- this.transitioningValue = false;
304
-
305
- if (!openState) {
306
- this._debug(
307
- "force hidden - complete",
308
- `${openState ? "open" : "closed"}`,
309
- target
310
- );
311
- target.hidden = !target.hidden;
312
- }
313
- this.openValue = openState;
314
-
315
- this._debug(
316
- "dispatching event",
317
- `reveal:${openState ? "shown" : "hidden"}`,
318
- target
319
- );
320
- target.dispatchEvent(
321
- new Event(`reveal:${openState ? "shown" : "hidden"}`, {
322
- bubbles: true,
323
- cancelable: false,
324
- })
325
- );
326
-
327
- if (this.hasAwayValue && openState) {
328
- document.addEventListener("click", this._awayHandler);
329
- }
330
-
331
- this._debug("dispatching event", "reveal:complete", target);
332
- target.dispatchEvent(
333
- new Event("reveal:complete", { bubbles: true, cancelable: false })
334
- );
335
- }
336
-
337
- /**
338
- * @private
339
- * @param {DOMElement} target
340
- * @param {boolean} openState
341
- */
342
- _transitionSetup(target, openState) {
343
- this.transitionType = openState ? "transitionEnter" : "transitionLeave";
344
-
345
- if (this.transitionType in target.dataset) {
346
- target.dataset.useTransitionClasses = true;
347
- const transitionClasses = this._transitionClasses(
348
- target,
349
- this.transitionType
350
- );
351
- target.classList.add(...transitionClasses.before.split(" "));
352
- target.classList.add(...transitionClasses.start.split(" "));
353
- } else {
354
- target.dataset.useTransitionClasses = false;
355
- const transitions = this._transitionDefaults(openState);
356
- target.dataset.opacityCache = target.style.opacity;
357
- target.dataset.transformCache = target.style.transform;
358
- target.dataset.transformOriginCache = target.style.transformOrigin;
359
-
360
- target.style.opacity = transitions.from.opacity;
361
- target.style.transform = `scale(${transitions.from.scale / 100})`;
362
- }
363
- if (openState) {
364
- this._debug("opening with transition", target);
365
- target.hidden = !target.hidden;
366
- }
367
- }
368
-
369
- /**
370
- * @private
371
- * @param {boolean} openState
372
- */
373
- _transitionDefaults(openState) {
374
- return {
375
- duration: openState ? 200 : 150,
376
- origin: "center",
377
- from: {
378
- opacity: openState ? 0 : 1,
379
- scale: openState ? 95 : 100,
380
- },
381
- to: {
382
- opacity: openState ? 1 : 0,
383
- scale: openState ? 100 : 95,
384
- },
385
- };
386
- }
387
-
388
- /**
389
- * @private
390
- * @param {DOMElement} target
391
- * @param {string} transitionType
392
- */
393
- _transitionClasses(target, transitionType) {
394
- return {
395
- before: target.dataset[transitionType],
396
- start: target.dataset[`${transitionType}Start`],
397
- end: target.dataset[`${transitionType}End`],
398
- };
399
- }
400
-
401
- /**
402
- * @private
403
- * @param {String} selector
404
- */
405
- _fetchElements(selector) {
406
- return [this.element, ...this.element.querySelectorAll(selector)].filter(
407
- (el) => el.matches(selector)
408
- );
409
- }
410
-
411
- /**
412
- * @private
413
- * @param {Array} args
414
- */
415
- _debug(...args) {
416
- if (this.debugValue) console.log(...args);
417
- }
418
-
419
- get selector() {
420
- return this.hasTargetSelectorValue
421
- ? this.targetSelectorValue
422
- : "[data-reveal]";
423
- }
424
- }
@@ -1,23 +0,0 @@
1
- module.exports = {
2
- content: [
3
- <%= Spina.config.tailwind_content.map{|path|"'#{path}'"}.join(",\n") %>
4
- ],
5
- theme: {
6
- fontFamily: {
7
- body: ['Metropolis'],
8
- mono: ['ui-monospace', 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', "Liberation Mono", "Courier New", 'monospace']
9
- },
10
- extend: {
11
- colors: {
12
- spina: {
13
- light: '#797ab8',
14
- DEFAULT: '#6865b4',
15
- dark: '#3a3a70'
16
- }
17
- }
18
- }
19
- },
20
- plugins: [
21
- <%= Spina.config.tailwind_plugins.map {|plugin|"require('#{plugin}')"}.join(",\n\t") %>
22
- ]
23
- }