maglevcms 1.5.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/app/components/maglev/page_component.rb +9 -7
  3. data/app/components/maglev/section_component.rb +34 -4
  4. data/app/controllers/concerns/maglev/content_locale_concern.rb +3 -1
  5. data/app/controllers/concerns/maglev/services_concern.rb +2 -1
  6. data/app/controllers/maglev/page_preview_controller.rb +2 -0
  7. data/app/frontend/admin/controllers/iframe_controller.js +1 -1
  8. data/app/frontend/admin/index.js +1 -1
  9. data/app/frontend/editor/components/kit/color-input/core-input.vue +2 -0
  10. data/app/frontend/editor/components/kit/color-input.vue +1 -1
  11. data/app/frontend/editor/components/kit/icon-input.vue +2 -2
  12. data/app/frontend/editor/components/kit/image-input.vue +2 -2
  13. data/app/frontend/editor/components/kit/link-input.vue +6 -2
  14. data/app/frontend/editor/components/kit/rich-text-input.vue +2 -2
  15. data/app/frontend/editor/components/kit/search-input.vue +1 -0
  16. data/app/frontend/editor/components/kit/select-input.vue +24 -20
  17. data/app/frontend/editor/components/kit/tabs.vue +12 -2
  18. data/app/frontend/editor/components/kit/text-input.vue +3 -2
  19. data/app/frontend/editor/components/kit/textarea-input.vue +4 -2
  20. data/app/frontend/editor/components/link-picker/index.vue +1 -1
  21. data/app/frontend/editor/components/page/edit.vue +2 -1
  22. data/app/frontend/editor/components/page/new.vue +2 -1
  23. data/app/frontend/editor/components/section-pane/index.vue +2 -1
  24. data/app/frontend/editor/services/section.js +1 -1
  25. data/app/frontend/editor/views/pages/edit.vue +1 -1
  26. data/app/frontend/live-preview-client/index.js +0 -1
  27. data/app/helpers/maglev/application_helper.rb +2 -1
  28. data/app/helpers/maglev/page_preview_helper.rb +14 -3
  29. data/app/models/maglev/setting_types/collection_item.rb +1 -1
  30. data/app/models/maglev/site/locales_concern.rb +1 -1
  31. data/app/services/maglev/fetch_site.rb +1 -1
  32. data/app/services/maglev/setup_pages.rb +3 -0
  33. data/app/views/maglev/admin/themes/_sections.html.erb +3 -3
  34. data/lib/generators/maglev/templates/install/config/initializers/maglev.rb +1 -1
  35. data/lib/maglev/version.rb +1 -1
  36. data/lib/maglev.rb +1 -1
  37. data/package.json +3 -3
  38. data/tailwind.config.js +10 -2
  39. data/yarn.lock +261 -14
  40. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f2ab19ced5aac5add6f9567d35c4ff2afd691a9df28d6427848add5b4e485c8
4
- data.tar.gz: 275f52591a49d27d99af9cd7d1d9e31204318c818cbc82bc02c7aba266336f23
3
+ metadata.gz: 45b336e791f110d5c7c1982631955c14664c2a66184b44b83a31f5689800d1d0
4
+ data.tar.gz: 65ea43f9f7006d128a21adad2c832f896d314715d83bc47283070ae60fb41dff
5
5
  SHA512:
6
- metadata.gz: d12fbd67952a61a321f253d6ec8ac8c97f981b880572bf3d8f1d65a95a825d29adba0041c53929c26a631a7f8e1f99e9bfbd907d82a53a263777ed9a751334f0
7
- data.tar.gz: 0a149c32927a7f9f478f489b281957a1f7ec32b5c2ee2ac3f08cfd6fad1d51ac59a6bca6f660af64f35bdc7833bec98443f23d9807ef5e515a22d112dee01f4a
6
+ metadata.gz: 17be0c14ba106d648cf9fa13953adff4e63f342a6d7d6acaa215cc6200f41c8d710e2d0b3c14d803f92ee4521c977f03b8c8389cd5351eb60bd87c23fbe50d73
7
+ data.tar.gz: 0adbc6d304a7b46cf1f4b1b6640fde924bad6d456931f0527adba2b01bcf3f06211f2cbe14f80c0fa93950f05d64eb01c7fb67cd136988d756103b2346b7c177
@@ -2,18 +2,19 @@
2
2
 
3
3
  module Maglev
4
4
  class PageComponent < BaseComponent
5
- attr_reader :site, :theme, :page, :page_sections, :templates_root_path, :config
5
+ attr_reader :site, :theme, :page, :page_sections, :templates_root_path, :config, :rendering_mode
6
6
 
7
- # rubocop:disable Lint/MissingSuper, Metrics/ParameterLists
8
- def initialize(site:, theme:, page:, page_sections:, templates_root_path:, config:)
7
+ # rubocop:disable Lint/MissingSuper
8
+ def initialize(site:, theme:, page:, page_sections:, context:)
9
9
  @site = site
10
10
  @theme = theme
11
11
  @page = page
12
12
  @page_sections = page_sections
13
- @templates_root_path = templates_root_path
14
- @config = config
13
+ @templates_root_path = context[:templates_root_path]
14
+ @config = context[:config]
15
+ @rendering_mode = context[:rendering_mode]
15
16
  end
16
- # rubocop:enable Lint/MissingSuper, Metrics/ParameterLists
17
+ # rubocop:enable Lint/MissingSuper
17
18
 
18
19
  # Sections within a dropzone
19
20
  def sections
@@ -37,7 +38,8 @@ module Maglev
37
38
  parent: self,
38
39
  definition: definition,
39
40
  attributes: attributes.deep_transform_keys! { |k| k.to_s.underscore.to_sym },
40
- templates_root_path: templates_root_path
41
+ templates_root_path: templates_root_path,
42
+ rendering_mode: rendering_mode
41
43
  )
42
44
  end
43
45
  end
@@ -7,16 +7,17 @@ module Maglev
7
7
  extend Forwardable
8
8
  def_delegators :parent, :site, :config
9
9
 
10
- attr_reader :parent, :id, :type, :settings, :attributes, :definition, :templates_root_path
10
+ attr_reader :parent, :id, :type, :settings, :attributes, :definition, :templates_root_path, :rendering_mode
11
11
 
12
12
  # rubocop:disable Lint/MissingSuper
13
- def initialize(parent:, attributes:, definition:, templates_root_path:)
13
+ def initialize(parent:, attributes:, definition:, templates_root_path:, rendering_mode:)
14
14
  @parent = parent # aka a PageComponent
15
15
  @id = attributes[:id]
16
16
  @type = attributes[:type]
17
17
  @definition = definition
18
18
  @attributes = attributes
19
19
  @templates_root_path = templates_root_path
20
+ @rendering_mode = rendering_mode
20
21
 
21
22
  @settings = settings_proxy(
22
23
  build_settings_map(attributes[:settings])
@@ -30,12 +31,12 @@ module Maglev
30
31
 
31
32
  # rubocop:disable Rails/OutputSafety
32
33
  def dom_data
33
- "data-maglev-section-id=\"#{id}\"".html_safe
34
+ "data-maglev-section-id=\"#{id}\" data-maglev-section-type=\"#{type}\"".html_safe
34
35
  end
35
36
  # rubocop:enable Rails/OutputSafety
36
37
 
37
38
  def tag_data
38
- { maglev_section_id: id }
39
+ { maglev_section_id: id, maglev_section_type: type }
39
40
  end
40
41
 
41
42
  def blocks
@@ -53,6 +54,8 @@ module Maglev
53
54
  template: "#{templates_root_path}/sections/#{definition.category}/#{type}",
54
55
  locals: { section: self, maglev_section: self }
55
56
  )
57
+ rescue StandardError => e
58
+ handle_error(e)
56
59
  end
57
60
 
58
61
  private
@@ -92,5 +95,32 @@ module Maglev
92
95
  attributes: block_attributes
93
96
  )
94
97
  end
98
+
99
+ def handle_error(exception)
100
+ throw exception if %i[live section].include?(rendering_mode) || Rails.env.test?
101
+
102
+ Rails.logger.error [
103
+ "⚠️ [Maglev] Error when rendering a \"#{type}\" type section ⚠️",
104
+ exception.message,
105
+ *exception.backtrace
106
+ ].join($INPUT_RECORD_SEPARATOR)
107
+
108
+ render_error
109
+ end
110
+
111
+ def render_error
112
+ <<~HTML
113
+ <div #{dom_data} style="padding: 5rem 0;">
114
+ <div style="max-width: 40rem; margin: 0 auto; background-color: rgb(254 242 242); color: rgb(153 27 27); padding: 1rem; border-radius: 0.375rem;">
115
+ <h3 style="font-weight: 500; color: rgb(153 27 27); font-size: 0.875rem; line-height: 1.25rem;">
116
+ We've encountered an error while rendering the <strong>"#{type}"</strong> section.
117
+ </h3>
118
+ <p style="margin-top: 0.5rem; font-size: 0.775rem; line-height: 1.25rem; color: rgb(185 28 28);">
119
+ Check out your application logs for more details.
120
+ </p>
121
+ </div>
122
+ </div>
123
+ HTML
124
+ end
95
125
  end
96
126
  end
@@ -5,7 +5,9 @@ module Maglev
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- helper_method :content_locale
8
+ alias_method :maglev_content_locale, :content_locale
9
+
10
+ helper_method :maglev_content_locale, :content_locale
9
11
  end
10
12
 
11
13
  private
@@ -24,7 +24,8 @@ module Maglev
24
24
  def build_maglev_service_context
25
25
  ::Maglev::ServiceContext.new(
26
26
  rendering_mode: maglev_rendering_mode,
27
- controller: self
27
+ controller: self,
28
+ site: nil
28
29
  )
29
30
  end
30
31
 
@@ -23,6 +23,8 @@ module Maglev
23
23
  super.tap do |site|
24
24
  raise ActiveRecord::RecordNotFound if site.nil?
25
25
 
26
+ maglev_services.context.site = site
27
+
26
28
  site.style = JSON.parse(params[:style]) if params[:style]
27
29
  end
28
30
  end
@@ -5,7 +5,7 @@ export default class extends Controller {
5
5
  this.element.addEventListener('load', () => {
6
6
  setTimeout(() => {
7
7
  let height =
8
- this.element.contentDocument.querySelector('body').clientHeight
8
+ this.element.contentDocument.querySelector('[data-maglev-section-id]').clientHeight
9
9
 
10
10
  if (height < 200) height = 200
11
11
 
@@ -4,7 +4,7 @@ import { Application } from 'stimulus'
4
4
  import { registerControllers } from 'stimulus-vite-helpers'
5
5
 
6
6
  const application = Application.start()
7
- const controllers = import.meta.globEager('./**/*_controller.js')
7
+ const controllers = import.meta.glob('./**/*_controller.js', { eager: true })
8
8
  registerControllers(application, controllers)
9
9
 
10
10
  window.stimulusApplication = application
@@ -11,6 +11,7 @@
11
11
  >
12
12
 
13
13
  <input
14
+ :id="name"
14
15
  type="text"
15
16
  :value="inputColor"
16
17
  @input="updateInput"
@@ -42,6 +43,7 @@ export default {
42
43
  name: 'CoreInput',
43
44
  components: { PresetDropdown },
44
45
  props: {
46
+ name: { type: String, default: 'color' },
45
47
  value: { type: String },
46
48
  presets: {
47
49
  type: Array,
@@ -6,7 +6,7 @@
6
6
  v-if="showLabel"
7
7
  >
8
8
  <span class="pr-2">{{ label }}</span>
9
- <core-input :presets="presets" v-model="updatableValue" />
9
+ <core-input :name="name" :presets="presets" v-model="updatableValue" />
10
10
  </label>
11
11
  </div>
12
12
  </template>
@@ -1,8 +1,8 @@
1
1
  <template>
2
2
  <div>
3
- <label class="block font-semibold text-gray-800" :for="name">
3
+ <div class="block font-semibold text-gray-800" @click="focus()">
4
4
  {{ label }}
5
- </label>
5
+ </div>
6
6
  <div class="mt-1">
7
7
  <div
8
8
  class="flex items-center justify-center bg-gray-100 h-24 rounded"
@@ -1,8 +1,8 @@
1
1
  <template>
2
2
  <div>
3
- <label class="block font-semibold text-gray-800" :for="name">
3
+ <div class="block font-semibold text-gray-800" @click="focus()">
4
4
  {{ label }}
5
- </label>
5
+ </div>
6
6
  <div class="mt-1">
7
7
  <div
8
8
  class="flex items-center justify-center bg-gray-100 h-48 rounded"
@@ -1,10 +1,11 @@
1
1
  <template>
2
2
  <div>
3
- <label class="block font-semibold text-gray-800" :for="name">
3
+ <div class="block font-semibold text-gray-800" @click="focus()">
4
4
  {{ label }}
5
- </label>
5
+ </div>
6
6
 
7
7
  <uikit-text-input
8
+ :name="name"
8
9
  v-model="textInput"
9
10
  :showLabel="false"
10
11
  :placeholder="$t('linkInput.nestedTextPlaceholder')"
@@ -82,6 +83,9 @@ export default {
82
83
  },
83
84
  },
84
85
  methods: {
86
+ focus() {
87
+ this.openLinkPickerModal()
88
+ },
85
89
  setLink(link) {
86
90
  this.$emit('input', {
87
91
  ...pick(
@@ -1,12 +1,12 @@
1
1
  <template>
2
2
  <div>
3
- <label
3
+ <div
4
4
  class="block font-semibold text-gray-800"
5
5
  :for="name"
6
6
  @click="focus()"
7
7
  >
8
8
  {{ label }}
9
- </label>
9
+ </div>
10
10
  <div class="mt-1">
11
11
  <editor-menu-bar :editor="editor" v-slot="{ commands, isActive }">
12
12
  <div class="flex sticky top-0 z-10 pb-2 bg-white space-x-1">
@@ -8,6 +8,7 @@
8
8
  </button>
9
9
 
10
10
  <input
11
+ name="search-input"
11
12
  type="text"
12
13
  v-model="query"
13
14
  class="block w-full border-0 bg-transparent focus:outline-none placeholder-gray-500"
@@ -1,12 +1,12 @@
1
1
  <template>
2
2
  <div>
3
- <label
3
+ <div
4
4
  class="block font-semibold text-gray-800"
5
- :for="name"
5
+ @click="focus()"
6
6
  v-if="withLabel"
7
7
  >
8
8
  {{ label }}
9
- </label>
9
+ </div>
10
10
  <div class="relative">
11
11
  <button
12
12
  class="text-left block w-full mt-1 py-2 px-3 rounded bg-gray-100 text-gray-800 focus:outline-none focus:ring"
@@ -51,6 +51,7 @@
51
51
  >
52
52
  <div class="px-3 pt-1 pb-3" v-if="searchEnabled">
53
53
  <input
54
+ :id="name"
54
55
  class="block mt-1 px-3 py-1 w-full border rounded border-gray-300 bg-gray-100 placeholder-gray-500 focus:ring focus:ring"
55
56
  type="text"
56
57
  v-model="q"
@@ -70,16 +71,16 @@
70
71
  class="py-1 px-4 cursor-pointer"
71
72
  :class="{
72
73
  'rounded-b': index === list.length - 1,
73
- 'bg-editor-primary text-white': index === focus,
74
+ 'bg-editor-primary text-white': index === focusIndex,
74
75
  }"
75
- @mouseover="focus = index"
76
- @mouseleave="focus = undefined"
76
+ @mouseover="focusIndex = index"
77
+ @mouseleave="focusIndex = undefined"
77
78
  @click="select(item)"
78
79
  >
79
80
  <slot
80
81
  name="item"
81
82
  v-bind:item="item"
82
- v-bind:hovered="index === focus"
83
+ v-bind:hovered="index === focusIndex"
83
84
  />
84
85
  </div>
85
86
  </div>
@@ -111,7 +112,7 @@ export default {
111
112
  isOpen: false,
112
113
  q: undefined,
113
114
  list: undefined,
114
- focus: undefined,
115
+ focusIndex: undefined,
115
116
  }
116
117
  },
117
118
  created() {
@@ -126,13 +127,16 @@ export default {
126
127
  },
127
128
  },
128
129
  methods: {
130
+ focus() {
131
+ this.toggle();
132
+ },
129
133
  toggle() {
130
134
  this.isOpen = !this.isOpen
131
135
  },
132
136
  fetch() {
133
137
  this.fetchList(this.q).then((list) => {
134
138
  this.list = list
135
- this.focus = list && list.length > 0 ? 0 : null
139
+ this.focusIndex = list && list.length > 0 ? 0 : null
136
140
  })
137
141
  },
138
142
  select(value) {
@@ -147,24 +151,24 @@ export default {
147
151
  if (!this) return
148
152
  switch (event.keyCode) {
149
153
  case 13:
150
- if (this.focus !== undefined) {
151
- this.select(this.list[this.focus])
154
+ if (this.focusIndex !== undefined) {
155
+ this.select(this.list[this.focusIndex])
152
156
  }
153
157
  event.stopPropagation() & event.preventDefault()
154
158
  break
155
159
  case 38:
156
- if (!this.focus) {
157
- this.focus = 0
158
- } else if (this.focus > 0) {
159
- this.focus--
160
+ if (!this.focusIndex) {
161
+ this.focusIndex = 0
162
+ } else if (this.focusIndex > 0) {
163
+ this.focusIndex--
160
164
  }
161
165
  event.stopPropagation() & event.preventDefault()
162
166
  break
163
167
  case 40:
164
- if (!this.focus) {
165
- this.focus = 0
166
- } else if (this.focus < this.list.length - 1) {
167
- this.focus++
168
+ if (!this.focusIndex) {
169
+ this.focusIndex = 0
170
+ } else if (this.focusIndex < this.list.length - 1) {
171
+ this.focusIndex++
168
172
  }
169
173
  event.stopPropagation() & event.preventDefault()
170
174
  break
@@ -174,7 +178,7 @@ export default {
174
178
  this.isOpen = false
175
179
  this.q = null
176
180
  this.list = undefined
177
- this.focus = undefined
181
+ this.focusIndex = undefined
178
182
  },
179
183
  },
180
184
  watch: {
@@ -3,7 +3,10 @@
3
3
  class="flex flex-col flex-1"
4
4
  :class="{ 'overflow-y-hidden': enableOverflow }"
5
5
  >
6
- <nav class="flex flex-col sm:flex-row" :class="sharedClass">
6
+ <nav class="flex flex-col sm:flex-row" :class="{
7
+ [sharedClass]: !isBlank(sharedClass),
8
+ [navClass]: !isBlank(navClass)
9
+ }">
7
10
  <button
8
11
  v-for="(tab, index) in tabs"
9
12
  :key="`tab-${index}`"
@@ -19,13 +22,17 @@
19
22
  {{ tab.name }}
20
23
  </button>
21
24
  </nav>
22
- <div class="relative -mt-1/2" :class="sharedClass">
25
+ <div class="relative -mt-1/2" :class="{
26
+ [sharedClass]: !isBlank(sharedClass),
27
+ [navClass]: !isBlank(navClass)
28
+ }">
23
29
  <div class="w-full border-gray-200 border-t-2 h-0"></div>
24
30
  </div>
25
31
  <div
26
32
  class="flex-1 mt-4 pb-4"
27
33
  :class="{
28
34
  [sharedClass]: !isBlank(sharedClass),
35
+ [panelClass]: !isBlank(panelClass),
29
36
  'overflow-y-auto': enableOverflow,
30
37
  }"
31
38
  >
@@ -35,6 +42,7 @@
35
42
  :key="currentTabKey"
36
43
  v-on="$listeners"
37
44
  v-bind="{ ...otherProps, ...currentTabProps }"
45
+ class="px-1"
38
46
  />
39
47
  </transition>
40
48
  </div>
@@ -48,6 +56,8 @@ export default {
48
56
  tabs: { type: Array, default: () => [] },
49
57
  firstIndex: { type: Number, default: 0 },
50
58
  otherProps: { type: Object, default: () => ({}) },
59
+ navClass: { type: String, default: null },
60
+ panelClass: { type: String, default: null },
51
61
  sharedClass: { type: String, default: null },
52
62
  enableOverflow: { type: Boolean, default: true },
53
63
  },
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="space-y-1">
2
+ <div class="space-y-1 flex flex-col">
3
3
  <label
4
4
  class="block font-semibold text-gray-800"
5
5
  :for="name"
@@ -15,12 +15,13 @@
15
15
  </transition>
16
16
  </label>
17
17
  <input
18
+ :id="name"
18
19
  type="text"
19
20
  :value="value"
20
21
  :placeholder="placeholder"
21
22
  @blur="blur()"
22
23
  @input="updateInput"
23
- class="block w-full py-2 px-3 rounded bg-gray-100 text-gray-800 focus:outline-none focus:ring placeholder-gray-500"
24
+ class="block py-2 px-3 rounded bg-gray-100 text-gray-800 focus:outline-none focus:ring placeholder-gray-500"
24
25
  autocomplete="off"
25
26
  ref="input"
26
27
  />
@@ -1,6 +1,7 @@
1
1
  <template>
2
- <div>
2
+ <div class="space-y-1 flex flex-col">
3
3
  <label
4
+ :for="name"
4
5
  class="block font-semibold text-gray-800 flex justify-between items-center"
5
6
  >
6
7
  <span>{{ label }}</span>
@@ -15,10 +16,11 @@
15
16
  >
16
17
  </label>
17
18
  <textarea
19
+ :id="name"
18
20
  :value="value"
19
21
  @blur="blur()"
20
22
  @input="updateInput"
21
- class="block w-full mt-1 py-2 px-3 rounded bg-gray-100 text-gray-800 focus:outline-none focus:ring"
23
+ class="block mt-1 py-2 px-3 rounded bg-gray-100 text-gray-800 focus:outline-none focus:ring"
22
24
  autocomplete="off"
23
25
  ref="input"
24
26
  :rows="rows"
@@ -4,7 +4,7 @@
4
4
  :tabs="tabs"
5
5
  :firstIndex="firstTabIndex"
6
6
  :otherProps="{ currentLink: link }"
7
- sharedClass="px-1/2"
7
+ navClass="px-1"
8
8
  :enableOverflow="false"
9
9
  @select-tab="onTabSelected"
10
10
  @change="onChange"
@@ -3,7 +3,8 @@
3
3
  <uikit-tabs
4
4
  :tabs="tabs"
5
5
  :otherProps="{ page: editedPage, errors }"
6
- sharedClass="px-1/2"
6
+ navClass="mx-4"
7
+ panelClass="mx-3"
7
8
  class="overflow-y-hidden pb-4"
8
9
  @on-change="onChange"
9
10
  />
@@ -3,7 +3,8 @@
3
3
  <uikit-tabs
4
4
  :tabs="tabs"
5
5
  :otherProps="{ page, errors }"
6
- sharedClass="px-1/2"
6
+ navClass="mx-1"
7
+ panelClass=""
7
8
  class="overflow-y-hidden pb-4"
8
9
  @on-change="onChange"
9
10
  />
@@ -4,7 +4,8 @@
4
4
  :firstIndex="tabIndexFromRoute"
5
5
  :otherProps="{ sectionId: currentSection.id, settingId }"
6
6
  class="overflow-y-hidden"
7
- sharedClass="px-4"
7
+ navClass="px-4"
8
+ panelClass="px-3"
8
9
  ref="tabs"
9
10
  />
10
11
  </template>
@@ -85,7 +85,7 @@ const buildSetting = (setting, sampleContent) => {
85
85
  let value = sampleContent ?? setting.default
86
86
  switch (setting.type) {
87
87
  case 'image':
88
- value = typeof value === 'string' ? { url: value } : {}
88
+ value = typeof value === 'string' ? { url: value } : value || {}
89
89
  break
90
90
  case 'link':
91
91
  value =
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <layout :title="$t('page.edit.currentPage.title')" :overflowY="false">
3
- <div class="flex flex-col flex-1 mx-4 pb-4 overflow-y-hidden">
3
+ <div class="flex flex-col flex-1 pb-4 overflow-y-hidden">
4
4
  <edit-page
5
5
  :page="currentPage"
6
6
  v-if="currentPage"
@@ -2,7 +2,6 @@ import { listenMessages } from './message'
2
2
 
3
3
  const start = () => {
4
4
  if (window.location === window.parent.location) {
5
- console.log('🚨 not in the Maglev editor')
6
5
  return false
7
6
  }
8
7
  listenMessages()
@@ -17,7 +17,8 @@ module Maglev
17
17
 
18
18
  entries = maglev_asset_manifest.resolve_entries(*%w[live-preview-rails-client], type: :javascript)
19
19
 
20
- javascript_include_tag(*entries.fetch(:scripts).flatten.uniq, crossorigin: 'anonymous', type: 'module')
20
+ javascript_include_tag(*entries.fetch(:scripts).flatten.uniq, crossorigin: 'anonymous', type: 'module',
21
+ defer: true)
21
22
  end
22
23
 
23
24
  def maglev_asset_manifest
@@ -9,8 +9,7 @@ module Maglev
9
9
  theme: theme || maglev_theme,
10
10
  page: page || maglev_page,
11
11
  page_sections: page_sections || maglev_page_sections,
12
- templates_root_path: maglev_sections_path,
13
- config: maglev_config
12
+ context: maglev_rendering_context
14
13
  ).tap { |component| component.view_context = self }.render.html_safe
15
14
  end
16
15
  # rubocop:enable Rails/OutputSafety
@@ -44,7 +43,7 @@ module Maglev
44
43
 
45
44
  def maglev_alt_link(locale, links: nil)
46
45
  links ||= maglev_page_fullpaths
47
- link = links[locale]
46
+ link = links[locale.to_sym]
48
47
  return nil if link.nil?
49
48
 
50
49
  "#{request.base_url}#{link}"
@@ -54,6 +53,18 @@ module Maglev
54
53
  maglev_site_root_fullpath
55
54
  end
56
55
 
56
+ def maglev_current_locale?(locale)
57
+ locale.to_sym == maglev_content_locale
58
+ end
59
+
60
+ def maglev_rendering_context
61
+ {
62
+ templates_root_path: maglev_sections_path,
63
+ rendering_mode: maglev_rendering_mode,
64
+ config: maglev_config
65
+ }
66
+ end
67
+
57
68
  def rendering_maglev_page?
58
69
  controller.class.module_parent.to_s == 'Maglev'
59
70
  end
@@ -4,7 +4,7 @@
4
4
  class Maglev::SettingTypes::CollectionItem < Maglev::SettingTypes::Base
5
5
  def cast_value(value)
6
6
  if value.is_a?(String)
7
- { id: default }
7
+ { id: value }
8
8
  else
9
9
  value
10
10
  end
@@ -6,7 +6,7 @@ module Maglev::Site::LocalesConcern
6
6
 
7
7
  included do
8
8
  ## serializers ##
9
- if Rails::VERSION::MAJOR > 6
9
+ if Rails::VERSION::MAJOR >= 7 && Rails::VERSION::MINOR.positive?
10
10
  serialize :locales, coder: LocalesSerializer
11
11
  else
12
12
  serialize :locales, LocalesSerializer
@@ -6,7 +6,7 @@ module Maglev
6
6
  include Injectable
7
7
 
8
8
  def call
9
- Maglev::Site.first.tap do |site|
9
+ @site ||= Maglev::Site.first.tap do |site|
10
10
  change_default_locales(site)
11
11
  end
12
12
  end
@@ -74,6 +74,9 @@ module Maglev
74
74
  def select_site_scoped_sections(sections)
75
75
  (sections || []).find_all do |section|
76
76
  definition = theme.sections.find(section['type'])
77
+
78
+ raise "[Maglev] Unknown section type: #{section['type']}" unless definition
79
+
77
80
  definition.site_scoped?
78
81
  end
79
82
  end