maglevcms 1.8.0 → 2.0.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.
- checksums.yaml +4 -4
- data/.yarn/install-state.gz +0 -0
- data/README.md +4 -4
- data/Rakefile +2 -1
- data/app/components/maglev/block_component.rb +1 -1
- data/app/components/maglev/content/base.rb +1 -1
- data/app/components/maglev/content/link.rb +4 -0
- data/app/components/maglev/section_component.rb +2 -2
- data/app/controllers/concerns/maglev/fetchers_concern.rb +3 -1
- data/app/controllers/concerns/maglev/resource_id_concern.rb +10 -0
- data/app/controllers/concerns/maglev/standalone_sections_concern.rb +6 -0
- data/app/controllers/concerns/maglev/{ui_locale_concern.rb → user_interface_locale_concern.rb} +1 -1
- data/app/controllers/maglev/api/collection_items_controller.rb +7 -0
- data/app/controllers/maglev/api/page_clones_controller.rb +1 -2
- data/app/controllers/maglev/api_controller.rb +1 -1
- data/app/controllers/maglev/application_controller.rb +1 -5
- data/app/controllers/maglev/assets/active_storage_proxy_controller.rb +17 -0
- data/app/controllers/maglev/assets/proxy_controller.rb +21 -0
- data/app/controllers/maglev/editor_controller.rb +1 -1
- data/app/controllers/maglev/page_preview_controller.rb +3 -3
- data/app/frontend/admin/controllers/screenshot_controller.js +29 -1
- data/app/frontend/editor/assets/remixicons/clipboard-line.svg +1 -0
- data/app/frontend/editor/assets/remixicons/ri-draggable.svg +1 -0
- data/app/frontend/editor/assets/remixicons/ri-folders-line.svg +1 -0
- data/app/frontend/editor/assets/remixicons/ri-more-fill.svg +1 -0
- data/app/frontend/editor/assets/remixicons/ri-shadow-line.svg +1 -0
- data/app/frontend/editor/components/errors/forbidden.vue +24 -0
- data/app/frontend/editor/components/errors/stale-record.vue +2 -2
- data/app/frontend/editor/components/header-nav/device-toggler.vue +6 -3
- data/app/frontend/editor/components/header-nav/index.vue +13 -42
- data/app/frontend/editor/components/header-nav/locale-toggler/index.vue +1 -1
- data/app/frontend/editor/components/header-nav/page-info.vue +41 -0
- data/app/frontend/editor/components/header-nav/preview-button.vue +6 -1
- data/app/frontend/editor/components/header-nav/separator.vue +1 -1
- data/app/frontend/editor/components/image-library/index.vue +26 -29
- data/app/frontend/editor/components/kit/collection-item-input.vue +9 -0
- data/app/frontend/editor/components/kit/copy-paste-button.vue +26 -0
- data/app/frontend/editor/components/kit/dropdown.vue +5 -0
- data/app/frontend/editor/components/kit/icon-button.vue +24 -0
- data/app/frontend/editor/components/kit/icon.vue +2 -3
- data/app/frontend/editor/components/kit/index.js +4 -2
- data/app/frontend/editor/components/kit/link-input.vue +1 -1
- data/app/frontend/editor/components/kit/modal.vue +1 -1
- data/app/frontend/editor/components/kit/page-icon.vue +1 -1
- data/app/frontend/editor/components/kit/rich-text-input/link-buttons.vue +1 -1
- data/app/frontend/editor/components/kit/select-input.vue +4 -2
- data/app/frontend/editor/components/link-picker/actions.vue +1 -1
- data/app/frontend/editor/components/link-picker/index.vue +1 -1
- data/app/frontend/editor/components/link-picker/page.vue +2 -0
- data/app/frontend/editor/components/page/form/main.vue +1 -1
- data/app/frontend/editor/components/page/list/actions-button.vue +159 -0
- data/app/frontend/editor/components/page/list/index.vue +15 -24
- data/app/frontend/editor/components/page/list/list-item.vue +10 -61
- data/app/frontend/editor/components/section-highlighter/index.vue +47 -46
- data/app/frontend/editor/components/section-list/add-button.vue +39 -0
- data/app/frontend/editor/components/section-list/index.vue +30 -15
- data/app/frontend/editor/components/section-list/list-item.vue +23 -8
- data/app/frontend/editor/components/section-pane/block-list/index.vue +1 -0
- data/app/frontend/editor/components/section-pane/block-list/list-item.vue +9 -6
- data/app/frontend/editor/components/section-pane/block-tree/new-nested-block-button.vue +2 -2
- data/app/frontend/editor/components/section-pane/block-tree/tree-node.vue +2 -2
- data/app/frontend/editor/components/sidebar-nav/index.vue +102 -0
- data/app/frontend/editor/components/sidebar-nav/link.vue +60 -0
- data/app/frontend/editor/components/theme-section-list/category.vue +47 -0
- data/app/frontend/editor/components/theme-section-list/index.vue +7 -31
- data/app/frontend/editor/components/theme-section-list/list-item.vue +10 -3
- data/app/frontend/editor/design/components/modal.scss +1 -1
- data/app/frontend/editor/design/components/tooltip.scss +6 -0
- data/app/frontend/editor/design/transitions.scss +1 -1
- data/app/frontend/editor/layouts/app.vue +14 -2
- data/app/frontend/editor/layouts/default.vue +2 -2
- data/app/frontend/editor/layouts/slide-pane.vue +1 -1
- data/app/frontend/editor/locales/editor.ar.json +265 -0
- data/app/frontend/editor/locales/editor.en.json +23 -15
- data/app/frontend/editor/locales/editor.es.json +18 -10
- data/app/frontend/editor/locales/editor.fr.json +28 -13
- data/app/frontend/editor/locales/editor.pt-BR.json +18 -10
- data/app/frontend/editor/locales/index.js +3 -0
- data/app/frontend/editor/mixins/error-modal.js +7 -2
- data/app/frontend/editor/mixins/preview-transformation.js +0 -1
- data/app/frontend/editor/plugins/i18n.js +2 -17
- data/app/frontend/editor/services/__tests__/section.spec.js +6 -0
- data/app/frontend/editor/services/collection-item.js +8 -0
- data/app/frontend/editor/services/live-preview.js +11 -1
- data/app/frontend/editor/services/page.js +1 -1
- data/app/frontend/editor/services/section.js +30 -0
- data/app/frontend/editor/services/site.js +4 -4
- data/app/frontend/editor/services/theme.js +1 -0
- data/app/frontend/editor/spec/__mocks__/page.js +3 -1
- data/app/frontend/editor/spec/__mocks__/services.js +1 -0
- data/app/frontend/editor/store/__tests__/getters.spec.js +56 -1
- data/app/frontend/editor/store/actions/index.js +1 -0
- data/app/frontend/editor/store/actions/site.js +8 -4
- data/app/frontend/editor/store/getters.js +11 -0
- data/app/frontend/editor/views/page-preview.vue +2 -1
- data/app/frontend/images/favicon.svg +11 -0
- data/app/frontend/images/logo.svg +14 -0
- data/app/frontend/live-preview-client/iframe-decorator.js +20 -17
- data/app/frontend/live-preview-client/message.js +1 -0
- data/app/frontend/live-preview-client/rails.js +12 -2
- data/app/helpers/maglev/application_helper.rb +7 -2
- data/app/helpers/maglev/editor_helper.rb +12 -5
- data/app/models/concerns/maglev/sections_concern.rb +4 -0
- data/app/models/maglev/asset.rb +13 -14
- data/app/models/maglev/page/path_concern.rb +23 -8
- data/app/models/maglev/page.rb +17 -18
- data/app/models/maglev/page_path.rb +18 -18
- data/app/models/maglev/section/setting.rb +1 -1
- data/app/models/maglev/section.rb +18 -9
- data/app/models/maglev/setting_types/link.rb +1 -1
- data/app/models/maglev/site.rb +13 -24
- data/app/services/maglev/app_container.rb +2 -2
- data/app/services/maglev/extract_locale.rb +3 -2
- data/app/services/maglev/fetch_page.rb +2 -0
- data/app/services/maglev/fetch_theme_layout.rb +2 -0
- data/app/services/maglev/get_page_fullpath.rb +1 -2
- data/app/services/maglev/remove_section_type.rb +50 -0
- data/app/services/maglev/rename_section_type.rb +57 -0
- data/app/services/maglev/search_pages.rb +2 -1
- data/app/views/layouts/maglev/admin/application.html.erb +1 -1
- data/app/views/maglev/admin/sections/previews/show.html.erb +16 -1
- data/app/views/maglev/api/collection_items/show.json.jbuilder +7 -0
- data/app/views/maglev/api/page_clones/create.json.jbuilder +3 -0
- data/app/views/maglev/editor/show.html.erb +6 -5
- data/config/locales/activerecord.ar.yml +13 -0
- data/config/locales/activerecord.en.yml +8 -2
- data/config/locales/activerecord.es.yml +4 -0
- data/config/locales/activerecord.fr.yml +6 -2
- data/config/locales/activerecord.pt-BR.yml +13 -0
- data/config/routes.rb +3 -4
- data/db/migrate/20200831101942_create_maglev_section_content.rb +10 -2
- data/db/migrate/20210819092740_switch_to_localized_page_fields.rb +13 -3
- data/db/migrate/20211008064437_add_locales_to_sites.rb +7 -1
- data/db/migrate/20211013210954_translate_section_content.rb +16 -2
- data/db/migrate/20211203224112_add_open_graph_tags_to_pages.rb +9 -3
- data/db/migrate/20220612092235_add_style_to_sites.rb +5 -1
- data/lib/commands/maglev/change_site_locales_command.rb +61 -0
- data/lib/commands/maglev/create_site_command.rb +28 -0
- data/lib/commands/maglev/sections/remove_command.rb +48 -0
- data/lib/commands/maglev/sections/rename_command.rb +49 -0
- data/lib/generators/maglev/templates/install/config/initializers/maglev.rb +4 -1
- data/lib/generators/maglev/templates/theme/app/views/theme/layout.html.erb.tt +8 -2
- data/lib/maglev/errors.rb +1 -0
- data/lib/maglev/preview_constraint.rb +5 -1
- data/lib/maglev/theme_filesystem_loader.rb +7 -0
- data/lib/maglev/version.rb +1 -1
- data/lib/maglev.rb +13 -3
- data/lib/tasks/maglev/icons.rake +123 -0
- data/lib/tasks/maglev/vite.rake +62 -0
- data/lib/tasks/maglev_tasks.rake +9 -107
- data/tailwind.config.js +1 -0
- metadata +48 -33
- data/app/controllers/maglev/assets_controller.rb +0 -10
- data/app/frontend/editor/components/kit/list-item-button.vue +0 -16
- data/app/frontend/editor/components/sidebar-nav.vue +0 -125
- data/app/frontend/editor/plugins/maglev_dummy.js +0 -2
- data/app/frontend/images/favicon.png +0 -0
- data/app/frontend/images/logo.png +0 -0
@@ -1,6 +1,7 @@
|
|
1
1
|
import axios from 'axios'
|
2
2
|
import { debounce } from './utils'
|
3
3
|
import runScripts from './run-scripts'
|
4
|
+
import { postMessage } from './message'
|
4
5
|
|
5
6
|
const parentDocument = window.parent.document
|
6
7
|
const previewDocument = window.document
|
@@ -21,6 +22,7 @@ const start = () => {
|
|
21
22
|
window.addEventListener('maglev:section:move', moveSections)
|
22
23
|
window.addEventListener('maglev:section:update', updateSection)
|
23
24
|
window.addEventListener('maglev:section:remove', removeSection)
|
25
|
+
window.addEventListener('maglev:section:ping', pingSection)
|
24
26
|
window.addEventListener('maglev:block:add', replaceSection)
|
25
27
|
window.addEventListener('maglev:block:move', replaceSection)
|
26
28
|
window.addEventListener('maglev:block:update', updateBlock)
|
@@ -71,10 +73,18 @@ const updateSection = (event) => {
|
|
71
73
|
const removeSection = (event) => {
|
72
74
|
const { sectionId } = event.detail
|
73
75
|
const selector = `[data-maglev-section-id='${sectionId}']`
|
74
|
-
|
76
|
+
const element = previewDocument.querySelector(selector)
|
75
77
|
element.remove()
|
76
78
|
}
|
77
79
|
|
80
|
+
const pingSection = (event) => {
|
81
|
+
const { sectionId } = event.detail
|
82
|
+
const selector = `[data-maglev-section-id='${sectionId}']`
|
83
|
+
const element = previewDocument.querySelector(selector)
|
84
|
+
// hack to force the highlighter bar to be updated with the correct dimensions
|
85
|
+
postMessage('scroll', { boundingRect: element.getBoundingClientRect() })
|
86
|
+
}
|
87
|
+
|
78
88
|
// === Block related actions ===
|
79
89
|
|
80
90
|
const updateBlock = (event) => {
|
@@ -166,7 +176,7 @@ const updatePreviewDocument = async (content, section, insertAt) => {
|
|
166
176
|
targetElement = previewDocument.querySelector(selector)
|
167
177
|
}
|
168
178
|
|
169
|
-
runScripts(
|
179
|
+
runScripts(sourceElement)
|
170
180
|
|
171
181
|
targetElement.scrollIntoView(true)
|
172
182
|
}
|
@@ -17,8 +17,13 @@ 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(
|
21
|
-
|
20
|
+
javascript_include_tag(
|
21
|
+
*entries.fetch(:scripts).flatten.uniq,
|
22
|
+
crossorigin: 'anonymous',
|
23
|
+
type: 'module',
|
24
|
+
defer: true,
|
25
|
+
nonce: true
|
26
|
+
)
|
22
27
|
end
|
23
28
|
|
24
29
|
def maglev_asset_manifest
|
@@ -20,7 +20,14 @@ module Maglev
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def editor_window_title
|
23
|
-
maglev_config.title
|
23
|
+
case maglev_config.title
|
24
|
+
when nil
|
25
|
+
'Maglev - EDITOR'
|
26
|
+
when String
|
27
|
+
maglev_config.title
|
28
|
+
when Proc
|
29
|
+
instance_exec(maglev_site, &maglev_config.title)
|
30
|
+
end
|
24
31
|
end
|
25
32
|
|
26
33
|
def editor_primary_hex_color
|
@@ -45,9 +52,9 @@ module Maglev
|
|
45
52
|
def editor_logo_url
|
46
53
|
case maglev_config.logo
|
47
54
|
when nil
|
48
|
-
editor_asset_path(nil, 'logo.
|
55
|
+
editor_asset_path(nil, 'logo.svg')
|
49
56
|
when String
|
50
|
-
editor_asset_path(maglev_config.logo, 'logo.
|
57
|
+
editor_asset_path(maglev_config.logo, 'logo.svg')
|
51
58
|
when Proc
|
52
59
|
instance_exec(maglev_site, &maglev_config.logo)
|
53
60
|
end
|
@@ -56,9 +63,9 @@ module Maglev
|
|
56
63
|
def editor_favicon_url
|
57
64
|
case maglev_config.favicon
|
58
65
|
when nil
|
59
|
-
editor_asset_path(nil, 'favicon.
|
66
|
+
editor_asset_path(nil, 'favicon.svg')
|
60
67
|
when String
|
61
|
-
editor_asset_path(maglev_config.favicon, 'favicon.
|
68
|
+
editor_asset_path(maglev_config.favicon, 'favicon.svg')
|
62
69
|
when Proc
|
63
70
|
instance_exec(maglev_site, &maglev_config.favicon)
|
64
71
|
end
|
data/app/models/maglev/asset.rb
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: maglev_assets
|
6
|
+
#
|
7
|
+
# id :bigint not null, primary key
|
8
|
+
# byte_size :integer
|
9
|
+
# content_type :string
|
10
|
+
# filename :string
|
11
|
+
# height :integer
|
12
|
+
# width :integer
|
13
|
+
# created_at :datetime not null
|
14
|
+
# updated_at :datetime not null
|
15
|
+
#
|
3
16
|
module Maglev
|
4
17
|
class Asset < ApplicationRecord
|
5
18
|
include ::Maglev.uploader
|
@@ -26,17 +39,3 @@ module Maglev
|
|
26
39
|
end
|
27
40
|
end
|
28
41
|
end
|
29
|
-
|
30
|
-
# == Schema Information
|
31
|
-
#
|
32
|
-
# Table name: maglev_assets
|
33
|
-
#
|
34
|
-
# id :bigint not null, primary key
|
35
|
-
# byte_size :integer
|
36
|
-
# content_type :string
|
37
|
-
# filename :string
|
38
|
-
# height :integer
|
39
|
-
# width :integer
|
40
|
-
# created_at :datetime not null
|
41
|
-
# updated_at :datetime not null
|
42
|
-
#
|
@@ -4,22 +4,32 @@
|
|
4
4
|
module Maglev::Page::PathConcern
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
+
COMMON_ASSOCIATION_PATH_OPTIONS = {
|
8
|
+
class_name: '::Maglev::PagePath',
|
9
|
+
foreign_key: 'maglev_page_id',
|
10
|
+
inverse_of: :page
|
11
|
+
}.freeze
|
12
|
+
|
7
13
|
included do
|
8
14
|
## associations ##
|
9
15
|
has_many :paths,
|
10
|
-
|
16
|
+
**COMMON_ASSOCIATION_PATH_OPTIONS,
|
11
17
|
dependent: :delete_all,
|
12
|
-
foreign_key: 'maglev_page_id',
|
13
|
-
inverse_of: :page,
|
14
18
|
autosave: true
|
15
19
|
|
20
|
+
# rubocop:disable Rails/HasManyOrHasOneDependent, Rails/InverseOf
|
21
|
+
has_many :canonical_paths,
|
22
|
+
-> { where(canonical: true) },
|
23
|
+
**COMMON_ASSOCIATION_PATH_OPTIONS
|
24
|
+
# rubocop:enable Rails/HasManyOrHasOneDependent, Rails/InverseOf
|
25
|
+
|
16
26
|
## callbacks ##
|
17
27
|
before_validation { path } # force the initialization of a new path if it doesn't exist
|
18
28
|
before_save :spawn_redirection, if: :spawn_redirection?
|
19
29
|
end
|
20
30
|
|
21
31
|
def default_path
|
22
|
-
@default_path ||=
|
32
|
+
@default_path ||= path_hash[Maglev::I18n.default_locale]
|
23
33
|
end
|
24
34
|
|
25
35
|
def path
|
@@ -38,13 +48,18 @@ module Maglev::Page::PathConcern
|
|
38
48
|
end
|
39
49
|
|
40
50
|
def current_path
|
41
|
-
locale = Maglev::I18n.current_locale
|
42
|
-
|
43
|
-
|
51
|
+
locale = Maglev::I18n.current_locale
|
52
|
+
canonical_path_hash[locale] ||= paths.build(locale: locale, canonical: true)
|
53
|
+
end
|
54
|
+
|
55
|
+
def canonical_path_hash
|
56
|
+
@canonical_path_hash ||= canonical_paths.to_a.each_with_object({}.with_indifferent_access) do |path, memo|
|
57
|
+
memo[path.locale] ||= path
|
58
|
+
end
|
44
59
|
end
|
45
60
|
|
46
61
|
def path_hash
|
47
|
-
|
62
|
+
canonical_path_hash.transform_values(&:value)
|
48
63
|
end
|
49
64
|
|
50
65
|
def disable_spawn_redirection
|
data/app/models/maglev/page.rb
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: maglev_pages
|
6
|
+
#
|
7
|
+
# id :bigint not null, primary key
|
8
|
+
# lock_version :integer
|
9
|
+
# meta_description_translations :jsonb
|
10
|
+
# og_description_translations :jsonb
|
11
|
+
# og_image_url_translations :jsonb
|
12
|
+
# og_title_translations :jsonb
|
13
|
+
# sections_translations :jsonb
|
14
|
+
# seo_title_translations :jsonb
|
15
|
+
# title_translations :jsonb
|
16
|
+
# visible :boolean default(TRUE)
|
17
|
+
# created_at :datetime not null
|
18
|
+
# updated_at :datetime not null
|
19
|
+
#
|
3
20
|
module Maglev
|
4
21
|
class Page < ApplicationRecord
|
5
22
|
## concerns ##
|
@@ -42,21 +59,3 @@ module Maglev
|
|
42
59
|
end
|
43
60
|
end
|
44
61
|
end
|
45
|
-
|
46
|
-
# == Schema Information
|
47
|
-
#
|
48
|
-
# Table name: maglev_pages
|
49
|
-
#
|
50
|
-
# id :bigint not null, primary key
|
51
|
-
# lock_version :integer
|
52
|
-
# meta_description_translations :jsonb
|
53
|
-
# og_description_translations :jsonb
|
54
|
-
# og_image_url_translations :jsonb
|
55
|
-
# og_title_translations :jsonb
|
56
|
-
# sections_translations :jsonb
|
57
|
-
# seo_title_translations :jsonb
|
58
|
-
# title_translations :jsonb
|
59
|
-
# visible :boolean default(TRUE)
|
60
|
-
# created_at :datetime not null
|
61
|
-
# updated_at :datetime not null
|
62
|
-
#
|
@@ -1,5 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: maglev_page_paths
|
6
|
+
#
|
7
|
+
# id :bigint not null, primary key
|
8
|
+
# canonical :boolean default(TRUE)
|
9
|
+
# locale :string not null
|
10
|
+
# value :string not null
|
11
|
+
# maglev_page_id :bigint
|
12
|
+
#
|
13
|
+
# Indexes
|
14
|
+
#
|
15
|
+
# canonical_speed (canonical,locale,value)
|
16
|
+
# index_maglev_page_paths_on_maglev_page_id (maglev_page_id)
|
17
|
+
# scoped_canonical_speed (canonical,maglev_page_id,locale)
|
18
|
+
#
|
3
19
|
module Maglev
|
4
20
|
class PagePath < ApplicationRecord
|
5
21
|
## associations ##
|
@@ -13,6 +29,7 @@ module Maglev
|
|
13
29
|
## validations ##
|
14
30
|
validates :value, presence: true, exclusion: { in: Maglev.config.reserved_paths }
|
15
31
|
validates :value, uniqueness: { scope: %i[locale canonical] }, if: :canonical?
|
32
|
+
validates :value, format: { without: /\s/, message: :invalid_path }
|
16
33
|
validates :canonical, uniqueness: { scope: %i[locale maglev_page_id] }, if: :canonical?
|
17
34
|
|
18
35
|
## callbacks ##
|
@@ -23,7 +40,7 @@ module Maglev
|
|
23
40
|
|
24
41
|
## class methods ##
|
25
42
|
|
26
|
-
def self.
|
43
|
+
def self.canonical_value_hash(page_id = nil)
|
27
44
|
query = page_id ? where(maglev_page_id: page_id) : all
|
28
45
|
query.canonical.pluck(:locale, :value).to_h
|
29
46
|
end
|
@@ -44,20 +61,3 @@ module Maglev
|
|
44
61
|
end
|
45
62
|
end
|
46
63
|
end
|
47
|
-
|
48
|
-
# == Schema Information
|
49
|
-
#
|
50
|
-
# Table name: maglev_page_paths
|
51
|
-
#
|
52
|
-
# id :bigint not null, primary key
|
53
|
-
# canonical :boolean default(TRUE)
|
54
|
-
# locale :string not null
|
55
|
-
# value :string not null
|
56
|
-
# maglev_page_id :bigint
|
57
|
-
#
|
58
|
-
# Indexes
|
59
|
-
#
|
60
|
-
# canonical_speed (canonical,locale,value)
|
61
|
-
# index_maglev_page_paths_on_maglev_page_id (maglev_page_id)
|
62
|
-
# scoped_canonical_speed (canonical,maglev_page_id,locale)
|
63
|
-
#
|
@@ -12,7 +12,7 @@ class Maglev::Section::Setting
|
|
12
12
|
attr_accessor :id, :label, :type, :default, :options
|
13
13
|
|
14
14
|
## validations ##
|
15
|
-
validates :id, :label, :type,
|
15
|
+
validates :id, :label, :type, 'maglev/presence': true
|
16
16
|
validates :type, inclusion: { in: REGISTERED_TYPES }
|
17
17
|
|
18
18
|
## methods ##
|
@@ -35,19 +35,28 @@ module Maglev
|
|
35
35
|
!!viewport_fixed_position?
|
36
36
|
end
|
37
37
|
|
38
|
+
def assign_attributes_from_yaml(hash)
|
39
|
+
attributes = prepare_default_attributes(hash).merge(
|
40
|
+
settings: ::Maglev::Section::Setting.build_many(hash['settings']),
|
41
|
+
blocks: ::Maglev::Section::Block.build_many(hash['blocks'])
|
42
|
+
)
|
43
|
+
|
44
|
+
assign_attributes(attributes)
|
45
|
+
end
|
46
|
+
|
38
47
|
## class methods ##
|
39
|
-
def self.build(hash)
|
40
|
-
attributes = prepare_attributes(hash)
|
41
48
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
)
|
47
|
-
)
|
49
|
+
def self.build(hash)
|
50
|
+
new.tap do |section|
|
51
|
+
section.assign_attributes_from_yaml(hash)
|
52
|
+
end
|
48
53
|
end
|
49
54
|
|
50
|
-
|
55
|
+
## private methods ##
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def prepare_default_attributes(hash)
|
51
60
|
attributes = hash.slice(*HASH_ATTRIBUTES)
|
52
61
|
|
53
62
|
%w[site_scoped singleton viewport_fixed_position max_width_pane].each do |name|
|
@@ -5,7 +5,7 @@ class Maglev::SettingTypes::Link < Maglev::SettingTypes::Base
|
|
5
5
|
def cast_value(value)
|
6
6
|
if value.is_a?(String)
|
7
7
|
{ text: 'Link', link_type: 'url', href: value }
|
8
|
-
|
8
|
+
elsif value
|
9
9
|
{ text: 'Link', link_type: 'url', href: '#' }.merge(value.symbolize_keys)
|
10
10
|
end
|
11
11
|
end
|
data/app/models/maglev/site.rb
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: maglev_sites
|
6
|
+
#
|
7
|
+
# id :bigint not null, primary key
|
8
|
+
# locales :jsonb
|
9
|
+
# lock_version :integer
|
10
|
+
# name :string
|
11
|
+
# sections_translations :jsonb
|
12
|
+
# style :jsonb
|
13
|
+
# created_at :datetime not null
|
14
|
+
# updated_at :datetime not null
|
15
|
+
#
|
3
16
|
module Maglev
|
4
17
|
class Site < ApplicationRecord
|
5
18
|
## concerns ##
|
@@ -27,27 +40,3 @@ module Maglev
|
|
27
40
|
end
|
28
41
|
end
|
29
42
|
end
|
30
|
-
|
31
|
-
# == Schema Information
|
32
|
-
#
|
33
|
-
# Table name: maglev_sites
|
34
|
-
#
|
35
|
-
# id :bigint not null, primary key
|
36
|
-
# domain :string
|
37
|
-
# handle :string
|
38
|
-
# locales :jsonb
|
39
|
-
# lock_version :integer
|
40
|
-
# name :string
|
41
|
-
# navigation :jsonb
|
42
|
-
# sections_translations :jsonb
|
43
|
-
# siteable_type :string
|
44
|
-
# style :jsonb
|
45
|
-
# created_at :datetime not null
|
46
|
-
# updated_at :datetime not null
|
47
|
-
# siteable_id :bigint
|
48
|
-
# theme_id :string
|
49
|
-
#
|
50
|
-
# Indexes
|
51
|
-
#
|
52
|
-
# index_maglev_sites_on_siteable (siteable_type,siteable_id)
|
53
|
-
#
|
@@ -23,7 +23,7 @@ module Maglev
|
|
23
23
|
|
24
24
|
dependency :fetch_collection_items, class: Maglev::FetchCollectionItems, depends_on: %i[fetch_site config]
|
25
25
|
dependency :fetch_static_pages, class: Maglev::FetchStaticPages, depends_on: %i[config]
|
26
|
-
dependency :search_pages, class: Maglev::SearchPages, depends_on: %i[fetch_site fetch_static_pages]
|
26
|
+
dependency :search_pages, class: Maglev::SearchPages, depends_on: %i[fetch_site fetch_static_pages context]
|
27
27
|
|
28
28
|
dependency :get_base_url, class: Maglev::GetBaseUrl, depends_on: %i[context fetch_site]
|
29
29
|
dependency :extract_locale, class: Maglev::ExtractLocale
|
@@ -34,7 +34,7 @@ module Maglev
|
|
34
34
|
dependency :add_site_locale, class: Maglev::AddSiteLocale
|
35
35
|
dependency :change_site_locales, class: Maglev::ChangeSiteLocales
|
36
36
|
|
37
|
-
dependency :fetch_page, class: Maglev::FetchPage, depends_on:
|
37
|
+
dependency :fetch_page, class: Maglev::FetchPage, depends_on: %i[context fetch_site]
|
38
38
|
dependency :get_page_fullpath, class: Maglev::GetPageFullpath, depends_on: %i[fetch_site get_base_url]
|
39
39
|
dependency :get_page_sections, class: Maglev::GetPageSections,
|
40
40
|
depends_on: %i[fetch_site fetch_theme
|
@@ -22,9 +22,10 @@ module Maglev
|
|
22
22
|
protected
|
23
23
|
|
24
24
|
def extract_locale
|
25
|
-
|
25
|
+
path = params[:path] || 'index'
|
26
|
+
segments = path.split('/')
|
26
27
|
|
27
|
-
return [default_locale,
|
28
|
+
return [default_locale, path] unless locales.include?(segments[0]&.to_sym)
|
28
29
|
|
29
30
|
[segments.shift, segments.empty? ? 'index' : segments.join('/')]
|
30
31
|
end
|
@@ -38,8 +38,7 @@ module Maglev
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def fetch_paths
|
41
|
-
|
42
|
-
Maglev::PagePath.build_hash(page_id)
|
41
|
+
page.respond_to?(:path_hash) ? page.path_hash : Maglev::PagePath.canonical_value_hash(page)
|
43
42
|
end
|
44
43
|
|
45
44
|
def build_fullpath(base_url, path)
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Maglev
|
4
|
+
# Remove all sections of a specific type across a site and its pages
|
5
|
+
class RemoveSectionType
|
6
|
+
include Injectable
|
7
|
+
|
8
|
+
argument :site
|
9
|
+
argument :type
|
10
|
+
|
11
|
+
def call
|
12
|
+
@removed_count = 0
|
13
|
+
|
14
|
+
remove_sections
|
15
|
+
|
16
|
+
@removed_count
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def remove_sections
|
22
|
+
ActiveRecord::Base.transaction do
|
23
|
+
remove_resource_sections(site)
|
24
|
+
site_pages.find_each do |page|
|
25
|
+
remove_resource_sections(page)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def remove_resource_sections(resource)
|
31
|
+
site.each_locale do
|
32
|
+
@removed_count += remove_sections_of_type(resource.sections, type)
|
33
|
+
end
|
34
|
+
|
35
|
+
resource.save!
|
36
|
+
end
|
37
|
+
|
38
|
+
def remove_sections_of_type(sections, type)
|
39
|
+
return 0 if sections.blank?
|
40
|
+
|
41
|
+
original_size = sections.size
|
42
|
+
sections.reject! { |section| section['type'] == type }
|
43
|
+
original_size - sections.size
|
44
|
+
end
|
45
|
+
|
46
|
+
def site_pages
|
47
|
+
Maglev::Page
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Maglev
|
4
|
+
# Rename all sections of a specific type to a new type across a site and its pages
|
5
|
+
class RenameSectionType
|
6
|
+
include Injectable
|
7
|
+
|
8
|
+
argument :site
|
9
|
+
argument :theme
|
10
|
+
argument :old_type
|
11
|
+
argument :new_type
|
12
|
+
|
13
|
+
def call
|
14
|
+
validate_section_types!
|
15
|
+
|
16
|
+
ActiveRecord::Base.transaction do
|
17
|
+
rename_resource_sections(site)
|
18
|
+
site_pages.find_each do |page|
|
19
|
+
rename_resource_sections(page)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def validate_section_types!
|
29
|
+
return if theme.sections.find(new_type)
|
30
|
+
|
31
|
+
raise Maglev::Errors::UnknownSection,
|
32
|
+
"New section type '#{new_type}' doesn't exist in the theme"
|
33
|
+
end
|
34
|
+
|
35
|
+
def rename_resource_sections(resource)
|
36
|
+
site.each_locale do |locale|
|
37
|
+
Maglev::I18n.with_locale(locale) do
|
38
|
+
change_section_type(resource.sections, old_type, new_type)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
resource.save!
|
43
|
+
end
|
44
|
+
|
45
|
+
def change_section_type(sections, old_type, new_type)
|
46
|
+
return if sections.blank?
|
47
|
+
|
48
|
+
sections.each do |section|
|
49
|
+
section['type'] = new_type if section['type'] == old_type
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def site_pages
|
54
|
+
Maglev::Page
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -9,6 +9,7 @@ module Maglev
|
|
9
9
|
|
10
10
|
dependency :fetch_site
|
11
11
|
dependency :fetch_static_pages
|
12
|
+
dependency :context
|
12
13
|
|
13
14
|
argument :id, default: nil
|
14
15
|
argument :q, default: nil
|
@@ -54,7 +55,7 @@ module Maglev
|
|
54
55
|
end
|
55
56
|
|
56
57
|
def resources
|
57
|
-
::Maglev::Page
|
58
|
+
::Maglev::Page.includes(:canonical_paths)
|
58
59
|
end
|
59
60
|
end
|
60
61
|
end
|
@@ -9,7 +9,7 @@
|
|
9
9
|
<%= vite_javascript_tag 'admin' %>
|
10
10
|
<%= vite_stylesheet_tag 'admin.scss' %>
|
11
11
|
|
12
|
-
<%= favicon_link_tag vite_asset_path 'images/favicon.
|
12
|
+
<%= favicon_link_tag vite_asset_path 'images/favicon.svg' %>
|
13
13
|
</head>
|
14
14
|
<body class="bg-gray-100">
|
15
15
|
<main role="main" class="container mx-auto">
|
@@ -12,11 +12,26 @@
|
|
12
12
|
Open in a new tab
|
13
13
|
<% end %>
|
14
14
|
<button
|
15
|
-
class="bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-purple-600 focus:ring-opacity-50 rounded text-white py-2 px-3"
|
15
|
+
class="bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-purple-600 focus:ring-opacity-50 rounded text-white py-2 px-3 mr-3"
|
16
16
|
data-action="click->screenshot#take"
|
17
17
|
>
|
18
18
|
Take screenshot
|
19
19
|
</button>
|
20
|
+
<div class="relative">
|
21
|
+
<button
|
22
|
+
class="bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-purple-600 focus:ring-opacity-50 rounded text-white py-2 px-3"
|
23
|
+
data-action="click->screenshot#triggerFileInput"
|
24
|
+
>
|
25
|
+
Upload screenshot
|
26
|
+
</button>
|
27
|
+
<input
|
28
|
+
type="file"
|
29
|
+
accept="image/*"
|
30
|
+
class="hidden"
|
31
|
+
data-screenshot-target="fileInput"
|
32
|
+
data-action="change->screenshot#handleFileUpload"
|
33
|
+
/>
|
34
|
+
</div>
|
20
35
|
</div>
|
21
36
|
</div>
|
22
37
|
<iframe
|