maglevcms 3.0.0.beta3 → 3.0.1
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/README.md +16 -53
- data/Rakefile +3 -1
- data/app/assets/builds/maglev/tailwind.css +424 -84
- data/app/assets/config/maglev_manifest.js +3 -2
- data/app/assets/javascripts/maglev/client/dom-operations.js +5 -5
- data/app/assets/javascripts/maglev/client/iframe-decorator.js +24 -0
- data/app/assets/javascripts/maglev/client/incoming-messages.js +13 -3
- data/app/assets/javascripts/maglev/client/index.js +3 -2
- data/app/assets/javascripts/maglev/client/utils.js +22 -0
- data/app/assets/javascripts/maglev/editor/controllers/app/forms/section_form_controller.js +4 -3
- data/app/assets/javascripts/maglev/editor/controllers/app/forms/style_form_controller.js +2 -1
- data/app/assets/javascripts/maglev/editor/controllers/app/page_preview_controller.js +96 -5
- data/app/assets/javascripts/maglev/editor/controllers/app/preview_notification_center_controller.js +105 -23
- data/app/assets/javascripts/maglev/editor/controllers/app/setting_controller.js +3 -2
- data/app/assets/javascripts/maglev/editor/controllers/shared/copy_to_clipboard_controller.js +2 -1
- data/app/assets/javascripts/maglev/editor/controllers/utils.js +22 -0
- data/app/assets/javascripts/maglev/editor/index.js +2 -1
- data/app/assets/javascripts/maglev/editor/patches/turbo_stream_patch.js +3 -3
- data/app/assets/stylesheets/maglev/tailwind.css.erb +8 -1
- data/app/components/maglev/content/link.rb +1 -1
- data/app/components/maglev/editor/settings/link/link_component.rb +7 -1
- data/app/components/maglev/section_component.rb +11 -1
- data/app/components/maglev/uikit/app_layout/sidebar/link_component.html.erb +1 -1
- data/app/components/maglev/uikit/app_layout/sidebar/link_component.rb +35 -5
- data/app/components/maglev/uikit/app_layout/sidebar_component.html.erb +3 -4
- data/app/components/maglev/uikit/app_layout/topbar_component.html.erb +1 -1
- data/app/components/maglev/uikit/app_layout/topbar_component.rb +1 -1
- data/app/components/maglev/uikit/button_group_component/button_group_component.html.erb +5 -0
- data/app/components/maglev/uikit/button_group_component.rb +70 -0
- data/app/components/maglev/uikit/device_toggler_component.rb +10 -1
- data/app/components/maglev/uikit/dropdown_component/dropdown_component.html.erb +2 -2
- data/app/components/maglev/uikit/dropdown_component.rb +6 -1
- data/app/components/maglev/uikit/form/color_field_component.html.erb +1 -1
- data/app/components/maglev/uikit/form/combobox_component.html.erb +1 -0
- data/app/components/maglev/uikit/form/link_component.rb +5 -1
- data/app/components/maglev/uikit/form/richtext_controller.js +5 -4
- data/app/components/maglev/uikit/form/search_form_component.html.erb +1 -0
- data/app/components/maglev/uikit/icon_component.rb +3 -0
- data/app/components/maglev/uikit/image_library/uploader_controller.js +3 -2
- data/app/components/maglev/uikit/list/list_item_component.html.erb +36 -19
- data/app/components/maglev/uikit/list/list_item_component.rb +19 -5
- data/app/components/maglev/uikit/locale_switcher_component/locale_switcher_component.html.erb +6 -10
- data/app/components/maglev/uikit/menu_dropdown_component/menu_dropdown_component.html.erb +6 -2
- data/app/components/maglev/uikit/menu_dropdown_component.rb +244 -7
- data/app/components/maglev/uikit/page_actions_dropdown_component/page_actions_dropdown_component.html.erb +39 -46
- data/app/components/maglev/uikit/pagination_component/pagination_component.html.erb +9 -12
- data/app/components/maglev/uikit/pagination_component.rb +6 -1
- data/app/components/maglev/uikit/section_toolbar/bottom_component.html.erb +1 -1
- data/app/components/maglev/uikit/tabs_component/tabs_component.html.erb +7 -4
- data/app/components/maglev/uikit/tabs_component.rb +23 -4
- data/app/components/maglev/uikit/well/simple_well_component.html.erb +15 -0
- data/app/components/maglev/uikit/well/simple_well_component.rb +13 -0
- data/app/controllers/concerns/maglev/editor/preview_urls_concern.rb +32 -0
- data/app/controllers/concerns/maglev/editor/turbo_concern.rb +29 -0
- data/app/controllers/concerns/maglev/flash_i18n_concern.rb +1 -0
- data/app/controllers/maglev/application_controller.rb +1 -1
- data/app/controllers/maglev/assets/active_storage_proxy_controller.rb +2 -1
- data/app/controllers/maglev/editor/assets_controller.rb +1 -1
- data/app/controllers/maglev/editor/base_controller.rb +6 -32
- data/app/controllers/maglev/editor/pages/clone_controller.rb +22 -0
- data/app/controllers/maglev/editor/pages/discard_draft_controller.rb +17 -0
- data/app/controllers/maglev/editor/pages_controller.rb +26 -7
- data/app/controllers/maglev/editor/section_blocks_controller.rb +13 -9
- data/app/controllers/maglev/editor/sections_controller.rb +26 -7
- data/app/controllers/maglev/published_page_preview_controller.rb +4 -0
- data/app/helpers/maglev/application_helper.rb +6 -6
- data/app/helpers/maglev/editor/section_blocks_helper.rb +2 -2
- data/app/models/maglev/page/publishable_concern.rb +69 -0
- data/app/models/maglev/page.rb +2 -13
- data/app/models/maglev/section/block.rb +4 -0
- data/app/models/maglev/section/content_concern.rb +3 -1
- data/app/models/maglev/section.rb +21 -1
- data/app/models/maglev/sections_content_store.rb +1 -3
- data/app/services/concerns/maglev/content/helpers_concern.rb +5 -8
- data/app/services/maglev/app_container.rb +4 -2
- data/app/services/maglev/discard_page_draft_service.rb +45 -0
- data/app/services/maglev/fetch_section_screenshot_url.rb +12 -1
- data/app/services/maglev/has_unpublished_changes.rb +21 -0
- data/app/services/maglev/publish_service.rb +15 -2
- data/app/views/layouts/maglev/editor/_sidebar.html.erb +6 -1
- data/app/views/layouts/maglev/editor/application.html.erb +5 -0
- data/app/views/layouts/maglev/editor/topbar/_page_info.html.erb +1 -1
- data/app/views/layouts/maglev/editor/topbar/_publish_button.html.erb +32 -10
- data/app/views/maglev/editor/assets/_list.html.erb +2 -1
- data/app/views/maglev/editor/assets/index.html.erb +1 -0
- data/app/views/maglev/editor/home/index.html.erb +1 -1
- data/app/views/maglev/editor/links/edit/_email.html.erb +1 -1
- data/app/views/maglev/editor/links/edit/_url.html.erb +1 -1
- data/app/views/maglev/editor/pages/_list.html.erb +25 -21
- data/app/views/maglev/editor/pages/_preview.html.erb +6 -6
- data/app/views/maglev/editor/pages/_preview_empty_message.html.erb +13 -10
- data/app/views/maglev/editor/pages/discard_draft/create.turbo_stream.erb +16 -0
- data/app/views/maglev/editor/pages/index.html.erb +8 -1
- data/app/views/maglev/editor/section_blocks/_form.html.erb +5 -13
- data/app/views/maglev/editor/section_blocks/_form_with_tabs.html.erb +15 -0
- data/app/views/maglev/editor/section_blocks/_new.html.erb +1 -1
- data/app/views/maglev/editor/section_blocks/edit.html.erb +2 -2
- data/app/views/maglev/editor/section_blocks/index/_list.html.erb +2 -2
- data/app/views/maglev/editor/section_blocks/index/_tree.html.erb +1 -1
- data/app/views/maglev/editor/section_blocks/update.turbo_stream.erb +1 -1
- data/app/views/maglev/editor/sections/_form.html.erb +6 -20
- data/app/views/maglev/editor/sections/_form_with_tabs.html.erb +21 -0
- data/app/views/maglev/editor/sections/_list.html.erb +3 -3
- data/app/views/maglev/editor/sections/edit.html.erb +4 -4
- data/app/views/maglev/editor/sections/index.html.erb +1 -1
- data/app/views/maglev/editor/sections/new.html.erb +19 -2
- data/app/views/maglev/editor/sections/theme/_empty_list.html.erb +3 -0
- data/app/views/maglev/editor/sections/theme/_list.html.erb +35 -0
- data/app/views/maglev/editor/sections/theme/_screenshot_placeholder.html.erb +6 -0
- data/app/views/maglev/editor/sections/theme/_search.html.erb +22 -0
- data/app/views/maglev/editor/sections/update.turbo_stream.erb +1 -1
- data/app/views/maglev/editor/shared/_button_label.html.erb +4 -4
- data/app/views/maglev/editor/style/edit.html.erb +1 -0
- data/config/editor_importmap.rb +13 -13
- data/config/locales/editor.ar.yml +12 -4
- data/config/locales/editor.en.yml +31 -23
- data/config/locales/editor.es.yml +12 -4
- data/config/locales/editor.fr.yml +12 -4
- data/config/locales/editor.pt-BR.yml +12 -4
- data/config/routes/maglev/assets.rb +4 -0
- data/config/routes/maglev/editor.rb +38 -0
- data/config/routes/maglev/preview.rb +8 -0
- data/config/routes/maglev/public_preview.rb +6 -0
- data/config/routes.rb +8 -47
- data/db/migrate/20211013210954_translate_section_content.rb +1 -0
- data/db/migrate/20260114112058_add_published_payload_to_pages.rb +14 -0
- data/exe/tailwind-cli +1 -1
- data/lib/generators/maglev/install_generator.rb +9 -7
- data/lib/generators/maglev/templates/install/config/initializers/maglev.rb +10 -3
- data/lib/maglev/active_storage/serving_blob.rb +29 -0
- data/lib/maglev/active_storage.rb +2 -0
- data/lib/maglev/config.rb +22 -3
- data/lib/maglev/engine.rb +14 -10
- data/lib/maglev/version.rb +1 -1
- data/lib/maglev.rb +18 -3
- data/lib/tasks/db_test_all.rake +290 -0
- metadata +46 -19
- data/app/controllers/maglev/editor/page_clone_controller.rb +0 -20
- data/app/views/maglev/editor/sections/_theme_list.html.erb +0 -32
- /data/vendor/javascript/{@floating-ui--core.js → maglev/@floating-ui--core.js} +0 -0
- /data/vendor/javascript/{@floating-ui--dom.js → maglev/@floating-ui--dom.js} +0 -0
- /data/vendor/javascript/{@floating-ui--utils--dom.js → maglev/@floating-ui--utils--dom.js} +0 -0
- /data/vendor/javascript/{@floating-ui--utils.js → maglev/@floating-ui--utils.js} +0 -0
- /data/vendor/javascript/{@hotwired--stimulus.js → maglev/@hotwired--stimulus.js} +0 -0
- /data/vendor/javascript/{@hotwired--turbo-rails.js → maglev/@hotwired--turbo-rails.js} +0 -0
- /data/vendor/javascript/{@hotwired--turbo.js → maglev/@hotwired--turbo.js} +0 -0
- /data/vendor/javascript/{@rails--actioncable--src.js → maglev/@rails--actioncable--src.js} +0 -0
- /data/vendor/javascript/{@rails--request.js.js → maglev/@rails--request.js.js} +0 -0
- /data/vendor/javascript/{@shopify--draggable.js → maglev/@shopify--draggable.js} +0 -0
- /data/vendor/javascript/{el-transition.js → maglev/el-transition.js} +0 -0
- /data/vendor/javascript/{stimulus-use.js → maglev/stimulus-use.js} +0 -0
- /data/vendor/javascript/{tiptap.bundle.js → maglev/tiptap.bundle.js} +0 -0
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
<%= render Maglev::Uikit::DropdownComponent.new(placement: placement) do |component| %>
|
|
1
|
+
<%= render Maglev::Uikit::DropdownComponent.new(placement: placement, wrapper_classes: wrapper_classes) do |component| %>
|
|
2
2
|
<% component.with_trigger do %>
|
|
3
3
|
<% if trigger.present? %>
|
|
4
4
|
<%= trigger %>
|
|
5
|
+
<% elsif trigger_classes.present? && icon_name.present? %>
|
|
6
|
+
<%= button_tag class: trigger_classes, data: { action: "click->uikit-dropdown#toggle", 'uikit-dropdown-target': 'button' } do %>
|
|
7
|
+
<%= render Maglev::Uikit::IconComponent.new(name: icon_name) %>
|
|
8
|
+
<% end %>
|
|
5
9
|
<% else %>
|
|
6
10
|
<%= render Maglev::Uikit::IconButtonComponent.new(icon_name: icon_name, data: { action: "click->uikit-dropdown#toggle", 'uikit-dropdown-target': 'button' }) %>
|
|
7
11
|
<% end %>
|
|
8
12
|
<% end %>
|
|
9
13
|
|
|
10
|
-
<div class="
|
|
14
|
+
<div class="<%= list_item_classes %>">
|
|
11
15
|
<% items.each do |item| %>
|
|
12
16
|
<%= item %>
|
|
13
17
|
<% end %>
|
|
@@ -3,30 +3,267 @@
|
|
|
3
3
|
module Maglev
|
|
4
4
|
module Uikit
|
|
5
5
|
class MenuDropdownComponent < Maglev::Uikit::BaseComponent
|
|
6
|
+
module RenderPolymorphicItems
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
included do
|
|
10
|
+
renders_many :items, types: {
|
|
11
|
+
button: lambda { |options = nil|
|
|
12
|
+
Maglev::Uikit::MenuDropdownComponent::ButtonItemComponent.new(options, parent: self)
|
|
13
|
+
},
|
|
14
|
+
link_to: lambda { |options = nil, html_options = nil|
|
|
15
|
+
Maglev::Uikit::MenuDropdownComponent::LinkToItemComponent.new(options, html_options, parent: self)
|
|
16
|
+
},
|
|
17
|
+
button_to: lambda { |options = nil, html_options = nil|
|
|
18
|
+
Maglev::Uikit::MenuDropdownComponent::ButtonToItemComponent.new(options, html_options, parent: self)
|
|
19
|
+
},
|
|
20
|
+
text: lambda { |options = nil|
|
|
21
|
+
Maglev::Uikit::MenuDropdownComponent::TextItemComponent.new(options, parent: self)
|
|
22
|
+
},
|
|
23
|
+
nested_menu: lambda { |placement:|
|
|
24
|
+
Maglev::Uikit::MenuDropdownComponent::NestedMenuComponent.new(placement: placement, parent: self)
|
|
25
|
+
},
|
|
26
|
+
wrapper: lambda { |options = nil|
|
|
27
|
+
Maglev::Uikit::MenuDropdownComponent::WrapperItemComponent.new(options, parent: self)
|
|
28
|
+
},
|
|
29
|
+
divider: -> { Maglev::Uikit::MenuDropdownComponent::DividerItemComponent.new(parent: self) }
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
6
34
|
renders_one :trigger
|
|
7
|
-
|
|
35
|
+
include RenderPolymorphicItems
|
|
8
36
|
|
|
9
|
-
attr_reader :icon_name, :placement
|
|
37
|
+
attr_reader :icon_name, :placement, :wrapper_classes, :trigger_classes
|
|
10
38
|
|
|
11
|
-
def initialize(icon_name: nil, placement: 'bottom-start')
|
|
39
|
+
def initialize(icon_name: nil, placement: 'bottom-start', wrapper_classes: nil, trigger_classes: nil)
|
|
12
40
|
@icon_name = icon_name
|
|
13
41
|
@placement = placement
|
|
42
|
+
@wrapper_classes = wrapper_classes
|
|
43
|
+
@trigger_classes = trigger_classes
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def list_item_classes
|
|
47
|
+
'text-gray-800 grid grid-cols-[auto_1fr_auto] min-w-[12rem] my-1'
|
|
14
48
|
end
|
|
15
49
|
|
|
50
|
+
# rubocop:disable Metrics/MethodLength
|
|
16
51
|
def item_classes(...)
|
|
17
52
|
class_variants(
|
|
18
53
|
base: %(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
54
|
+
col-span-3 grid grid-cols-subgrid
|
|
55
|
+
flex flex-1 items-center px-2 py-3 w-full mx-1 rounded-sm text-left
|
|
56
|
+
transition-colors duration-200 focus:outline-none cursor-pointer
|
|
57
|
+
),
|
|
58
|
+
variants: {
|
|
59
|
+
danger: 'text-red-600 hover:bg-red-100',
|
|
60
|
+
'!danger': 'hover:bg-gray-100',
|
|
61
|
+
subdued: 'text-gray-400'
|
|
62
|
+
},
|
|
63
|
+
defaults: { danger: false, subdued: false }
|
|
22
64
|
).render(...)
|
|
23
65
|
end
|
|
66
|
+
# rubocop:enable Metrics/MethodLength
|
|
24
67
|
|
|
25
68
|
def form_item_classes(...)
|
|
26
69
|
class_variants(
|
|
27
|
-
base:
|
|
70
|
+
base: %w[
|
|
71
|
+
col-span-3 grid grid-cols-subgrid
|
|
72
|
+
flex items-center focus:outline-none cursor-pointer
|
|
73
|
+
]
|
|
28
74
|
).render(...)
|
|
29
75
|
end
|
|
76
|
+
|
|
77
|
+
class ItemComponent < ViewComponent::Base
|
|
78
|
+
renders_one :icon
|
|
79
|
+
renders_one :label
|
|
80
|
+
renders_one :sub_label
|
|
81
|
+
renders_one :right_icon
|
|
82
|
+
|
|
83
|
+
def self.inner_content
|
|
84
|
+
<<-ERB
|
|
85
|
+
<%= render Maglev::Uikit::IconComponent.new(name: icon.to_s, size: '1.15rem', class_names: 'mr-2 shrink-0') if icon? %>
|
|
86
|
+
<span class="<%= 'col-start-2' unless icon? %> whitespace-nowrap whitespace-nowrap truncate overflow-hidden">
|
|
87
|
+
<%= label %>
|
|
88
|
+
</span>
|
|
89
|
+
<%= render Maglev::Uikit::IconComponent.new(name: 'arrow_right', size: '1.15rem', class_names: 'ml-2 shrink-0') if right_arrow? %>
|
|
90
|
+
<span class="col-start-2 whitespace-nowrap whitespace-nowrap truncate overflow-hidden text-xs text-gray-500">
|
|
91
|
+
<%= sub_label %>
|
|
92
|
+
</span>
|
|
93
|
+
ERB
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def right_arrow?
|
|
97
|
+
false
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
class TextItemComponent < ItemComponent
|
|
102
|
+
attr_reader :options, :parent_component, :variant
|
|
103
|
+
|
|
104
|
+
def initialize(options = nil, parent: nil)
|
|
105
|
+
@parent_component = parent
|
|
106
|
+
@options = options || {}
|
|
107
|
+
@variant = @options.delete(:variant)
|
|
108
|
+
|
|
109
|
+
apply_parent_classes
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
erb_template <<-ERB
|
|
113
|
+
<%= tag.span(**options) do %>
|
|
114
|
+
#{inner_content}
|
|
115
|
+
<% end %>
|
|
116
|
+
ERB
|
|
117
|
+
|
|
118
|
+
private
|
|
119
|
+
|
|
120
|
+
def apply_parent_classes
|
|
121
|
+
options[:class] = parent_component.item_classes(subdued: variant == 'subdued', class: options[:class])
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
class LinkToItemComponent < ItemComponent
|
|
126
|
+
attr_reader :options, :html_options, :parent_component, :variant
|
|
127
|
+
|
|
128
|
+
def initialize(options = nil, html_options = nil, parent: nil)
|
|
129
|
+
@parent_component = parent
|
|
130
|
+
@options = options
|
|
131
|
+
@html_options = html_options || {}
|
|
132
|
+
@variant = @html_options.delete(:variant)
|
|
133
|
+
|
|
134
|
+
apply_parent_classes
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
erb_template <<-ERB
|
|
138
|
+
<%= link_to options, html_options do %>
|
|
139
|
+
#{inner_content}
|
|
140
|
+
<% end %>
|
|
141
|
+
ERB
|
|
142
|
+
|
|
143
|
+
private
|
|
144
|
+
|
|
145
|
+
def apply_parent_classes
|
|
146
|
+
html_options[:class] = parent_component.item_classes(danger: variant == 'danger', class: html_options[:class])
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
class ButtonItemComponent < ItemComponent
|
|
151
|
+
attr_reader :options, :parent_component
|
|
152
|
+
|
|
153
|
+
def initialize(options = nil, parent: nil)
|
|
154
|
+
@parent_component = parent
|
|
155
|
+
@options = (options || {}).merge(type: 'button')
|
|
156
|
+
|
|
157
|
+
apply_parent_classes
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
erb_template <<-ERB
|
|
161
|
+
<%= button_tag options do %>
|
|
162
|
+
#{inner_content}
|
|
163
|
+
<% end %>
|
|
164
|
+
ERB
|
|
165
|
+
|
|
166
|
+
private
|
|
167
|
+
|
|
168
|
+
def apply_parent_classes
|
|
169
|
+
options[:class] = parent_component.item_classes(class: options[:class])
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
class ButtonToItemComponent < LinkToItemComponent
|
|
174
|
+
erb_template <<-ERB
|
|
175
|
+
<%= button_to options, html_options do %>
|
|
176
|
+
#{inner_content}
|
|
177
|
+
<% end %>
|
|
178
|
+
ERB
|
|
179
|
+
|
|
180
|
+
private
|
|
181
|
+
|
|
182
|
+
def apply_parent_classes
|
|
183
|
+
super
|
|
184
|
+
html_options[:form_class] = parent_component.form_item_classes(class: html_options[:form_class])
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
class NestedMenuComponent < ItemComponent
|
|
189
|
+
include RenderPolymorphicItems
|
|
190
|
+
|
|
191
|
+
attr_reader :placement, :parent_component
|
|
192
|
+
|
|
193
|
+
delegate :list_item_classes, :item_classes, :form_item_classes, to: :parent_component
|
|
194
|
+
|
|
195
|
+
alias wrapper_classes form_item_classes
|
|
196
|
+
|
|
197
|
+
def initialize(placement:, parent:)
|
|
198
|
+
@placement = placement
|
|
199
|
+
@parent_component = parent
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
erb_template <<-ERB
|
|
203
|
+
<%= render Maglev::Uikit::DropdownComponent.new(placement: placement, wrapper_classes: wrapper_classes) do |dropdown| %>
|
|
204
|
+
<% dropdown.with_trigger do %>
|
|
205
|
+
<%= button_tag class: item_classes, data: { action: 'click->uikit-dropdown#toggle', 'uikit-dropdown-target': 'button' } do %>
|
|
206
|
+
#{inner_content}#{' '}
|
|
207
|
+
<% end %>
|
|
208
|
+
<% end %>
|
|
209
|
+
|
|
210
|
+
<div class="<%= list_item_classes %>">
|
|
211
|
+
<% items.each do |item| %>
|
|
212
|
+
<%= item %>
|
|
213
|
+
<% end %>
|
|
214
|
+
</div>
|
|
215
|
+
<% end %>
|
|
216
|
+
ERB
|
|
217
|
+
|
|
218
|
+
def right_arrow?
|
|
219
|
+
true
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
class WrapperItemComponent < Maglev::Uikit::BaseComponent
|
|
224
|
+
include RenderPolymorphicItems
|
|
225
|
+
|
|
226
|
+
attr_reader :options, :parent_component
|
|
227
|
+
|
|
228
|
+
delegate :item_classes, :form_item_classes, to: :parent_component
|
|
229
|
+
|
|
230
|
+
def initialize(options, parent: nil)
|
|
231
|
+
@parent_component = parent
|
|
232
|
+
@options = options || {}
|
|
233
|
+
|
|
234
|
+
apply_parent_classes
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
erb_template <<-ERB
|
|
238
|
+
<%= tag.div(**options) do %>
|
|
239
|
+
<% items.each do |item| %>
|
|
240
|
+
<%= item %>
|
|
241
|
+
<% end %>
|
|
242
|
+
<% end %>
|
|
243
|
+
ERB
|
|
244
|
+
|
|
245
|
+
private
|
|
246
|
+
|
|
247
|
+
def apply_parent_classes
|
|
248
|
+
options[:class] = parent_component.form_item_classes(class: options[:class])
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
class DividerItemComponent < ItemComponent
|
|
253
|
+
attr_reader :parent_component
|
|
254
|
+
|
|
255
|
+
def initialize(parent:)
|
|
256
|
+
@parent_component = parent
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def item_classes(...)
|
|
260
|
+
parent_component.form_item_classes(class: 'border-t border-gray-200 my-1 px-0!')
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
erb_template <<-ERB
|
|
264
|
+
<%= tag.hr class: item_classes %>
|
|
265
|
+
ERB
|
|
266
|
+
end
|
|
30
267
|
end
|
|
31
268
|
end
|
|
32
269
|
end
|
|
@@ -1,56 +1,49 @@
|
|
|
1
|
-
<%= render Maglev::Uikit::MenuDropdownComponent.new(icon_name: icon_name) do |
|
|
2
|
-
<%
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<span class="ml-2 whitespace-nowrap truncate overflow-hidden"><%= t('maglev.editor.pages.actions.edit') %></span>
|
|
6
|
-
<% end %>
|
|
1
|
+
<%= render Maglev::Uikit::MenuDropdownComponent.new(icon_name: icon_name) do |menu_dropdown| %>
|
|
2
|
+
<% menu_dropdown.with_item_link_to(paths[:edit], data: { turbo_frame: '_top' }) do |menu_item| %>
|
|
3
|
+
<% menu_item.with_icon_content('settings') %>
|
|
4
|
+
<% menu_item.with_label_content(t('maglev.editor.pages.actions.edit')) %>
|
|
7
5
|
<% end if allow?(:edit) %>
|
|
8
6
|
|
|
9
|
-
<%
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<%
|
|
17
|
-
<% sub_menu.with_item do %>
|
|
18
|
-
<%= link_to t('maglev.editor.pages.actions.draft_preview'), paths[:preview], class: sub_menu.item_classes, target: '_blank' %>
|
|
19
|
-
<% end %>
|
|
20
|
-
<% sub_menu.with_item do %>
|
|
21
|
-
<%= link_to t('maglev.editor.pages.actions.live_preview'), live_url, class: sub_menu.item_classes, target: '_blank' %>
|
|
22
|
-
<% end %>
|
|
7
|
+
<% menu_dropdown.with_item_divider if allow?(:edit) %>
|
|
8
|
+
|
|
9
|
+
<% menu_dropdown.with_item_nested_menu(placement: 'right-start') do |menu_item| %>
|
|
10
|
+
<% menu_item.with_icon_content('preview') %>
|
|
11
|
+
<% menu_item.with_label_content(t('maglev.editor.pages.actions.preview')) %>
|
|
12
|
+
|
|
13
|
+
<% menu_item.with_item_link_to(paths[:preview], target: '_blank') do |sub_menu_item| %>
|
|
14
|
+
<% sub_menu_item.with_label_content(t('maglev.editor.pages.actions.draft_preview')) %>
|
|
23
15
|
<% end %>
|
|
24
|
-
<% end if allow?(:preview) %>
|
|
25
16
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
17
|
+
<% menu_item.with_item_link_to(live_url, target: '_blank') do |sub_menu_item| %>
|
|
18
|
+
<% sub_menu_item.with_label_content(t('maglev.editor.pages.actions.live_preview')) %>
|
|
19
|
+
<% end if live_url.present? %>
|
|
20
|
+
|
|
21
|
+
<% menu_item.with_item_text(variant: 'subdued') do |text_item| %>
|
|
22
|
+
<% text_item.with_label_content(t('maglev.editor.pages.actions.no_live_preview')) %>
|
|
23
|
+
<% end if live_url.blank? %>
|
|
24
|
+
<% end %>
|
|
25
|
+
|
|
26
|
+
<% menu_dropdown.with_item_wrapper(data: { controller: 'copy-to-clipboard', copy_to_clipboard_source_value: live_url }) do |wrapper_item| %>
|
|
27
|
+
<% wrapper_item.with_item_button(data: { copy_to_clipboard_target: 'text', action: 'click->copy-to-clipboard#copy:prevent' }) do |menu_item| %>
|
|
28
|
+
<% menu_item.with_icon_content('clipboard') %>
|
|
29
|
+
<% menu_item.with_label_content(t('maglev.editor.pages.actions.copy_url_to_clipboard')) %>
|
|
30
30
|
<% end %>
|
|
31
|
-
<% end if allow?(:clone) %>
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<span class="ml-2 whitespace-nowrap truncate overflow-hidden">
|
|
38
|
-
<%= t('maglev.editor.pages.actions.copy_url_to_clipboard') %>
|
|
39
|
-
</span>
|
|
40
|
-
<% end %>
|
|
41
|
-
<div class="<%= dropdown.item_classes %> hidden" data-copy-to-clipboard-target="success">
|
|
42
|
-
<%= render Maglev::Uikit::IconComponent.new(name: 'checkbox_circle', class_names: 'text-green-500 shrink-0') %>
|
|
43
|
-
<span class="ml-2 whitespace-nowrap truncate overflow-hidden text-green-500">
|
|
44
|
-
<%= t('maglev.editor.pages.actions.copy_url_to_clipboard_success') %>
|
|
45
|
-
</span>
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
32
|
+
<% wrapper_item.with_item_button(class: 'hidden text-green-500', data: { copy_to_clipboard_target: 'success' }) do |menu_item| %>
|
|
33
|
+
<% menu_item.with_icon_content('checkbox_circle') %>
|
|
34
|
+
<% menu_item.with_label_content(t('maglev.editor.pages.actions.copy_url_to_clipboard_success')) %>
|
|
35
|
+
<% end %>
|
|
48
36
|
<% end if allow?(:copy_url_to_clipboard) %>
|
|
49
37
|
|
|
50
|
-
<%
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
<%
|
|
38
|
+
<% menu_dropdown.with_item_divider if allow?(:clone) || allow?(:delete) %>
|
|
39
|
+
|
|
40
|
+
<% menu_dropdown.with_item_button_to(paths[:clone], data: { turbo_frame: '_top' }) do |menu_item| %>
|
|
41
|
+
<% menu_item.with_icon_content('clone') %>
|
|
42
|
+
<% menu_item.with_label_content(t('maglev.editor.pages.actions.clone')) %>
|
|
43
|
+
<% end if allow?(:clone) %>
|
|
44
|
+
|
|
45
|
+
<% menu_dropdown.with_item_button_to(paths[:delete], method: :delete, variant: 'danger', data: { turbo_confirm: t('maglev.editor.pages.actions.confirm_delete'), turbo_frame: '_top' }) do |menu_item| %>
|
|
46
|
+
<% menu_item.with_icon_content('delete_bin') %>
|
|
47
|
+
<% menu_item.with_label_content(t('maglev.editor.pages.actions.delete')) %>
|
|
55
48
|
<% end if allow?(:delete) %>
|
|
56
49
|
<% end %>
|
|
@@ -27,20 +27,17 @@
|
|
|
27
27
|
<% end %>
|
|
28
28
|
</div>
|
|
29
29
|
|
|
30
|
-
<div class="hidden sm:flex sm:flex-1 sm:items-center sm:justify-between">
|
|
31
|
-
|
|
32
|
-
<p class="text-sm">
|
|
30
|
+
<div class="hidden sm:flex sm:flex-1 sm:items-center <%= show_info? ? 'sm:justify-between' : 'sm:justify-center' %>">
|
|
31
|
+
<p class="text-sm <%= 'hidden' unless show_info? %>">
|
|
33
32
|
<%== pagy_info(pagy, item_name: item_name) %>
|
|
34
|
-
</p>
|
|
35
|
-
</div>
|
|
33
|
+
</p>
|
|
36
34
|
|
|
37
|
-
<div class="<%= 'hidden' if pagy.series.size == 1 %>">
|
|
38
35
|
<nav class="isolate inline-flex gap-1" aria-label="Pages">
|
|
39
36
|
<%# Previous page link %>
|
|
40
37
|
<% if pagy.prev %>
|
|
41
|
-
<%== a.(pagy.prev, left_arrow, aria_label: 'Previous', classes: 'relative inline-flex items-center rounded-
|
|
38
|
+
<%== a.(pagy.prev, left_arrow, aria_label: 'Previous', classes: 'relative inline-flex items-center rounded-xs px-1 py-1 text-gray-400 hover:bg-gray-100 focus:z-20 focus:outline-offset-0') %>
|
|
42
39
|
<% else %>
|
|
43
|
-
<a role="link" aria-disabled="true" aria-label="Previous" class="relative inline-flex items-center rounded-
|
|
40
|
+
<a role="link" aria-disabled="true" aria-label="Previous" class="relative inline-flex items-center rounded-xs px-1 py-1 text-gray-400 hover:bg-gray-100 focus:z-20 focus:outline-offset-0">
|
|
44
41
|
<%= left_arrow %>
|
|
45
42
|
</a>
|
|
46
43
|
<% end %>
|
|
@@ -48,9 +45,9 @@
|
|
|
48
45
|
<%# Page links (series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]) %>
|
|
49
46
|
<% pagy.series.each do |item| %>
|
|
50
47
|
<% if item.is_a?(Integer) %>
|
|
51
|
-
<%== a.(item, classes: 'relative inline-flex items-center px-2.5 py-1 text-sm font-semibold text-gray-900 hover:bg-gray-100 focus:z-20 focus:outline-offset-0') %>
|
|
48
|
+
<%== a.(item, classes: 'relative inline-flex items-center px-2.5 py-1 text-sm font-semibold text-gray-900 rounded-xs hover:bg-gray-100 focus:z-20 focus:outline-offset-0') %>
|
|
52
49
|
<% elsif item.is_a?(String) %>
|
|
53
|
-
<a role="link" aria-disabled="true" aria-current="page" class="relative z-10 inline-flex items-center bg-editor-primary px-2.5 py-1 text-sm font-semibold text-white focus:z-20"><%= item %></a>
|
|
50
|
+
<a role="link" aria-disabled="true" aria-current="page" class="relative z-10 inline-flex items-center rounded-xs bg-editor-primary px-2.5 py-1 text-sm font-semibold text-white focus:z-20"><%= item %></a>
|
|
54
51
|
<% elsif item == :gap %>
|
|
55
52
|
<a role="link" aria-disabled="true" class="relative inline-flex items-center px-2.5 py-1 text-sm font-semibold text-gray-700 focus:outline-offset-0">…</a>
|
|
56
53
|
<% end %>
|
|
@@ -58,9 +55,9 @@
|
|
|
58
55
|
|
|
59
56
|
<%# Next page link %>
|
|
60
57
|
<% if pagy.next %>
|
|
61
|
-
<%== a.(pagy.next, right_arrow, aria_label: 'Next', classes: 'relative inline-flex items-center rounded-
|
|
58
|
+
<%== a.(pagy.next, right_arrow, aria_label: 'Next', classes: 'relative inline-flex items-center rounded-xs px-1 py-1 text-gray-400 hover:bg-gray-100 focus:z-20 focus:outline-offset-0') %>
|
|
62
59
|
<% else %>
|
|
63
|
-
<a role="link" aria-disabled="true" aria-label="Next" class="relative inline-flex items-center rounded-
|
|
60
|
+
<a role="link" aria-disabled="true" aria-label="Next" class="relative inline-flex items-center rounded-xs px-1 py-1 text-gray-400 hover:bg-gray-100 focus:z-20 focus:outline-offset-0">
|
|
64
61
|
<%= right_arrow %>
|
|
65
62
|
</a>
|
|
66
63
|
<% end %>
|
|
@@ -7,10 +7,11 @@ module Maglev
|
|
|
7
7
|
|
|
8
8
|
attr_reader :pagy, :hidden_if_single_page
|
|
9
9
|
|
|
10
|
-
def initialize(pagy:, item_name: 'item', hidden_if_single_page: true)
|
|
10
|
+
def initialize(pagy:, item_name: 'item', hidden_if_single_page: true, show_info: true)
|
|
11
11
|
@pagy = pagy
|
|
12
12
|
@hidden_if_single_page = hidden_if_single_page
|
|
13
13
|
@item_name = item_name
|
|
14
|
+
@show_info = show_info
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def item_name
|
|
@@ -20,6 +21,10 @@ module Maglev
|
|
|
20
21
|
def render?
|
|
21
22
|
!(hidden_if_single_page && pagy.pages < 2)
|
|
22
23
|
end
|
|
24
|
+
|
|
25
|
+
def show_info?
|
|
26
|
+
@show_info
|
|
27
|
+
end
|
|
23
28
|
end
|
|
24
29
|
end
|
|
25
30
|
end
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
data-transition-leave-start="translate-y-0 opacity-100"
|
|
8
8
|
data-transition-leave-end="translate-y-[50%] opacity-0"
|
|
9
9
|
>
|
|
10
|
-
<%= link_to paths[:add], class: button_classes, data: { turbo_frame: '
|
|
10
|
+
<%= link_to paths[:add], class: button_classes, data: { turbo_frame: 'modal' } do %>
|
|
11
11
|
<%= render Maglev::Uikit::IconComponent.new(name: 'add') %>
|
|
12
12
|
<% end if insert_button? %>
|
|
13
13
|
</div>
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
<input type="hidden" name="active_tab" value="<%= active_tab_index %>" data-uikit-tabs-target="hiddenInput" />
|
|
9
9
|
|
|
10
10
|
<nav>
|
|
11
|
-
<ul class="flex flex-
|
|
11
|
+
<ul class="flex flex-row">
|
|
12
12
|
<% tabs.each_with_index do |tab, index| %>
|
|
13
|
-
<li>
|
|
13
|
+
<li class="shrink-0">
|
|
14
14
|
<% if tab.link? %>
|
|
15
15
|
<%= link_to tab.label, tab.link[:url], class: label_classes(active: tab.active?), **tab.link_html_options %>
|
|
16
16
|
<% else %>
|
|
@@ -25,11 +25,14 @@
|
|
|
25
25
|
</ul>
|
|
26
26
|
</nav>
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
<% if variant == :default %>
|
|
29
|
+
<div class="relative -mt-0.5"><div class="w-full border-gray-200 border-t-2 h-0"></div></div>
|
|
30
|
+
<% end %>
|
|
29
31
|
|
|
30
32
|
<% tabs.each_with_index do |tab, index| %>
|
|
33
|
+
<% next unless tab.block? %>
|
|
31
34
|
<div data-uikit-tabs-target="tabContent" class="flex-1 mt-4 pt-2 pb-4 overflow-y-auto overflow-x-visible <%= 'hidden' unless tab.active? %>">
|
|
32
|
-
<%= capture(&tab.block)
|
|
35
|
+
<%= capture(&tab.block) %>
|
|
33
36
|
</div>
|
|
34
37
|
<% end %>
|
|
35
38
|
</div>
|
|
@@ -7,16 +7,21 @@ module Maglev
|
|
|
7
7
|
Tab.new(self, label: label, active: active, link: link, block: block)
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
attr_reader :container_classes, :active_tab, :active_tab_index, :disable_inputs
|
|
10
|
+
attr_reader :container_classes, :active_tab, :active_tab_index, :disable_inputs, :variant
|
|
11
11
|
|
|
12
12
|
# disable_inputs: true | false (default: false) if true, the inputs of hidden tabs will not be submitted
|
|
13
|
-
def initialize(container_classes: nil, active_tab_index: nil, disable_inputs: false)
|
|
13
|
+
def initialize(container_classes: nil, active_tab_index: nil, disable_inputs: false, variant: :default)
|
|
14
14
|
@container_classes = container_classes
|
|
15
15
|
@active_tab_index = active_tab_index
|
|
16
16
|
@disable_inputs = disable_inputs
|
|
17
|
+
@variant = variant
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
def label_classes(...)
|
|
21
|
+
variant == :pills ? pills_label_classes(...) : default_label_classes(...)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def default_label_classes(...)
|
|
20
25
|
class_variants(
|
|
21
26
|
base: %(
|
|
22
27
|
relative py-1 pb-0 px-4 block focus:outline-none border-b-2
|
|
@@ -29,9 +34,23 @@ module Maglev
|
|
|
29
34
|
).render(...)
|
|
30
35
|
end
|
|
31
36
|
|
|
37
|
+
def pills_label_classes(...)
|
|
38
|
+
class_variants(
|
|
39
|
+
base: %(rounded-md px-3 py-2 text-sm),
|
|
40
|
+
variants: {
|
|
41
|
+
active: 'rounded-md bg-editor-primary/10 font-semibold text-editor-primary',
|
|
42
|
+
'!active': 'text-gray-500 hover:text-gray-700 font-medium'
|
|
43
|
+
}
|
|
44
|
+
).render(...)
|
|
45
|
+
end
|
|
46
|
+
|
|
32
47
|
def before_render
|
|
33
|
-
@active_tab = tabs.find(&:active?)
|
|
34
|
-
|
|
48
|
+
@active_tab = tabs.find(&:active?)
|
|
49
|
+
|
|
50
|
+
return unless !@active_tab && active_tab_index != -1
|
|
51
|
+
|
|
52
|
+
@active_tab = tabs[active_tab_index.to_i]
|
|
53
|
+
@active_tab&.active = true
|
|
35
54
|
end
|
|
36
55
|
|
|
37
56
|
def disable_inputs?
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<div class="bg-gray-50 sm:rounded-lg">
|
|
2
|
+
<div class="px-4 py-5 sm:p-6">
|
|
3
|
+
<h3 class="text-base font-semibold text-gray-900">
|
|
4
|
+
<%= title %>
|
|
5
|
+
</h3>
|
|
6
|
+
<div class="mt-2 max-w-xl text-sm text-gray-500 space-y-2">
|
|
7
|
+
<%= description %>
|
|
8
|
+
</div>
|
|
9
|
+
<% if action? %>
|
|
10
|
+
<div class="mt-5">
|
|
11
|
+
<%= action %>
|
|
12
|
+
</div>
|
|
13
|
+
<% end %>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Maglev
|
|
4
|
+
module Editor
|
|
5
|
+
module PreviewUrlsConcern
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
helper_method :current_maglev_page_urls, :maglev_page_live_url, :maglev_page_preview_url
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def current_maglev_page_urls
|
|
15
|
+
{
|
|
16
|
+
path: maglev_services.get_page_fullpath.call(page: current_maglev_page, preview_mode: false,
|
|
17
|
+
locale: content_locale),
|
|
18
|
+
preview: maglev_page_preview_url(current_maglev_page),
|
|
19
|
+
live: maglev_page_live_url(current_maglev_page)
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def maglev_page_live_url(page)
|
|
24
|
+
maglev_services.get_page_fullpath.call(page: page, preview_mode: false, locale: content_locale)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def maglev_page_preview_url(page)
|
|
28
|
+
maglev_services.get_page_fullpath.call(page: page, preview_mode: true, locale: content_locale)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Maglev
|
|
4
|
+
module Editor
|
|
5
|
+
module TurboConcern
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
helper_method :maglev_disable_turbo_cache?
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def maglev_disable_turbo_cache
|
|
15
|
+
@maglev_disable_turbo_cache = true
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def maglev_disable_turbo_cache?
|
|
19
|
+
!!@maglev_disable_turbo_cache
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def ensure_turbo_frame_request
|
|
23
|
+
return if turbo_frame_request?
|
|
24
|
+
|
|
25
|
+
redirect_to editor_root_path
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|