alchemy_cms 8.0.0.a → 8.0.0.c
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 +3 -0
- data/app/assets/builds/alchemy/admin/page-select.css +1 -1
- data/app/assets/builds/alchemy/admin.css +1 -1
- data/app/assets/builds/alchemy/dark-theme.css +1 -0
- data/app/assets/builds/alchemy/light-theme.css +1 -0
- data/app/assets/builds/alchemy/theme.css +1 -0
- data/app/assets/builds/alchemy/welcome.css +1 -1
- data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css +1 -1
- data/app/assets/builds/tinymce/skins/content/alchemy-dark/content.min.css +1 -0
- data/app/assets/builds/tinymce/skins/ui/alchemy/skin.min.css +1 -1
- data/app/assets/builds/tinymce/skins/ui/alchemy-dark/content.min.css +1 -0
- data/app/assets/builds/tinymce/skins/ui/alchemy-dark/skin.min.css +1 -0
- data/app/assets/images/alchemy/element_icons/layout-bottom-2-line.svg +1 -0
- data/app/assets/images/alchemy/icons-sprite.svg +1 -1
- data/app/components/alchemy/admin/element_select.rb +39 -0
- data/app/components/alchemy/admin/link_dialog/tabs.rb +1 -1
- data/app/components/alchemy/admin/locale_select.rb +38 -0
- data/app/components/alchemy/ingredients/datetime_view.rb +4 -2
- data/app/controllers/alchemy/admin/attachments_controller.rb +2 -0
- data/app/controllers/alchemy/admin/elements_controller.rb +2 -0
- data/app/controllers/alchemy/admin/pages_controller.rb +3 -1
- data/app/controllers/alchemy/admin/pictures_controller.rb +26 -34
- data/app/controllers/alchemy/admin/resources_controller.rb +1 -1
- data/app/controllers/alchemy/pages_controller.rb +19 -2
- data/app/controllers/concerns/alchemy/admin/resource_filter.rb +1 -0
- data/app/decorators/alchemy/ingredient_editor.rb +9 -1
- data/app/helpers/alchemy/admin/attachments_helper.rb +5 -5
- data/app/helpers/alchemy/admin/base_helper.rb +0 -7
- data/app/helpers/alchemy/admin/form_helper.rb +2 -1
- data/app/helpers/alchemy/pages_helper.rb +1 -1
- data/app/javascript/alchemy_admin/components/auto_submit.js +20 -0
- data/app/javascript/alchemy_admin/components/datepicker.js +8 -5
- data/app/javascript/alchemy_admin/components/element_editor/delete_element_button.js +3 -2
- data/app/javascript/alchemy_admin/components/element_editor.js +25 -15
- data/app/javascript/alchemy_admin/components/element_select.js +43 -0
- data/app/javascript/alchemy_admin/components/index.js +5 -0
- data/app/javascript/alchemy_admin/components/link_buttons.js +6 -2
- data/app/javascript/alchemy_admin/components/remote_select.js +5 -1
- data/app/javascript/alchemy_admin/components/tinymce.js +93 -16
- data/app/javascript/alchemy_admin/dialog.js +1 -1
- data/app/javascript/alchemy_admin/file_editors.js +1 -1
- data/app/javascript/alchemy_admin/image_loader.js +4 -2
- data/app/javascript/alchemy_admin/picture_editors.js +7 -4
- data/app/javascript/alchemy_admin/picture_selector.js +4 -4
- data/app/jobs/alchemy/delete_picture_job.rb +12 -0
- data/app/models/alchemy/attachment.rb +2 -9
- data/app/models/alchemy/element.rb +1 -0
- data/app/models/alchemy/element_definition.rb +31 -0
- data/app/models/alchemy/ingredient.rb +1 -1
- data/app/models/alchemy/ingredients/boolean.rb +2 -1
- data/app/models/alchemy/language.rb +2 -7
- data/app/models/alchemy/page/page_naming.rb +4 -11
- data/app/models/alchemy/page/page_natures.rb +16 -11
- data/app/models/alchemy/page/publisher.rb +1 -1
- data/app/models/alchemy/page.rb +1 -6
- data/app/models/alchemy/page_definition.rb +1 -1
- data/app/models/alchemy/picture.rb +6 -17
- data/app/models/alchemy/resource.rb +15 -2
- data/app/models/alchemy/site/layout.rb +1 -0
- data/app/models/alchemy/site.rb +1 -6
- data/app/models/alchemy/storage_adapter/dragonfly/picture_url.rb +7 -2
- data/app/models/alchemy/storage_adapter/dragonfly.rb +24 -2
- data/app/models/concerns/alchemy/relatable_resource.rb +28 -0
- data/app/stylesheets/alchemy/_custom-properties.scss +162 -0
- data/app/stylesheets/alchemy/_mixins.scss +12 -24
- data/app/stylesheets/alchemy/_themes.scss +540 -0
- data/app/stylesheets/alchemy/admin/archive.scss +28 -8
- data/app/stylesheets/alchemy/admin/attachments.scss +10 -33
- data/app/stylesheets/alchemy/admin/base.scss +4 -1
- data/app/stylesheets/alchemy/admin/buttons.scss +7 -32
- data/app/stylesheets/alchemy/admin/dashboard.scss +13 -0
- data/app/stylesheets/alchemy/admin/dialogs.scss +17 -7
- data/app/stylesheets/alchemy/admin/element-select.scss +11 -0
- data/app/stylesheets/alchemy/admin/elements.scss +95 -34
- data/app/stylesheets/alchemy/admin/filters.scss +8 -9
- data/app/stylesheets/alchemy/admin/flatpickr.scss +12 -27
- data/app/stylesheets/alchemy/admin/form_fields.scss +0 -15
- data/app/stylesheets/alchemy/admin/forms.scss +3 -8
- data/app/stylesheets/alchemy/admin/frame.scss +5 -7
- data/app/stylesheets/alchemy/admin/icons.scss +0 -9
- data/app/stylesheets/alchemy/admin/image_library.scss +13 -55
- data/app/stylesheets/alchemy/admin/navigation.scss +1 -11
- data/app/stylesheets/alchemy/admin/node-select.scss +1 -10
- data/app/stylesheets/alchemy/admin/nodes.scss +6 -2
- data/app/stylesheets/alchemy/admin/notices.scss +5 -4
- data/app/stylesheets/alchemy/admin/page-select.scss +16 -0
- data/app/stylesheets/alchemy/admin/pagination.scss +1 -8
- data/app/stylesheets/alchemy/admin/preview_window.scss +12 -1
- data/app/stylesheets/alchemy/admin/resource_info.scss +106 -3
- data/app/stylesheets/alchemy/admin/search.scss +1 -1
- data/app/stylesheets/alchemy/admin/selects.scss +58 -31
- data/app/stylesheets/alchemy/admin/shoelace.scss +32 -62
- data/app/stylesheets/alchemy/admin/sitemap.scss +7 -18
- data/app/stylesheets/alchemy/admin/tables.scss +3 -3
- data/app/stylesheets/alchemy/admin/tags.scss +18 -35
- data/app/stylesheets/alchemy/admin/toolbar.scss +0 -6
- data/app/stylesheets/alchemy/admin/typography.scss +2 -5
- data/app/stylesheets/alchemy/admin.scss +1 -1
- data/app/stylesheets/alchemy/dark-theme.scss +5 -0
- data/app/stylesheets/alchemy/light-theme.scss +6 -0
- data/app/stylesheets/alchemy/theme.scss +13 -0
- data/app/stylesheets/tinymce/skins/content/alchemy/content.scss +8 -8
- data/app/stylesheets/tinymce/skins/content/alchemy-dark/content.scss +70 -0
- data/app/stylesheets/tinymce/skins/ui/alchemy/skin.scss +28 -43
- data/app/stylesheets/tinymce/skins/ui/alchemy-dark/content.scss +1 -0
- data/app/stylesheets/tinymce/skins/ui/alchemy-dark/skin.scss +3784 -0
- data/app/views/alchemy/admin/attachments/_files_list.html.erb +20 -10
- data/app/views/alchemy/admin/attachments/assign.js.erb +4 -3
- data/app/views/alchemy/admin/attachments/show.html.erb +55 -43
- data/app/views/alchemy/admin/crop.html.erb +1 -1
- data/app/views/alchemy/admin/dashboard/index.html.erb +1 -1
- data/app/views/alchemy/admin/dashboard/info.html.erb +36 -6
- data/app/views/alchemy/admin/elements/_form.html.erb +9 -9
- data/app/views/alchemy/admin/elements/_header.html.erb +12 -10
- data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +1 -1
- data/app/views/alchemy/admin/nodes/_form.html.erb +5 -1
- data/app/views/alchemy/admin/pages/info.html.erb +1 -1
- data/app/views/alchemy/admin/partials/_search_form.html.erb +1 -0
- data/app/views/alchemy/admin/pictures/_archive.html.erb +13 -23
- data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +1 -6
- data/app/views/alchemy/admin/pictures/_form.html.erb +10 -5
- data/app/views/alchemy/admin/pictures/_infos.html.erb +21 -52
- data/app/views/alchemy/admin/pictures/_library_sidebar.html.erb +7 -0
- data/app/views/alchemy/admin/pictures/_picture.html.erb +15 -16
- data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +20 -16
- data/app/views/alchemy/admin/pictures/_sorting_select.html.erb +13 -0
- data/app/views/alchemy/admin/pictures/_tag_list.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/edit_multiple.html.erb +1 -6
- data/app/views/alchemy/admin/pictures/index.html.erb +3 -12
- data/app/views/alchemy/admin/pictures/show.html.erb +17 -14
- data/app/views/alchemy/admin/pictures/update.turbo_stream.erb +1 -1
- data/app/views/alchemy/admin/resources/_filter_bar.html.erb +5 -15
- data/app/views/alchemy/admin/resources/_resource_usage_info.html.erb +36 -0
- data/app/views/alchemy/admin/styleguide/index.html.erb +118 -66
- data/app/views/alchemy/admin/uploader/_button.html.erb +1 -1
- data/app/views/alchemy/base/error_notice.html.erb +1 -1
- data/app/views/alchemy/ingredients/_page_editor.html.erb +0 -1
- data/app/views/alchemy/ingredients/_richtext_editor.html.erb +0 -1
- data/app/views/alchemy/ingredients/_select_editor.html.erb +1 -2
- data/app/views/layouts/alchemy/admin.html.erb +25 -23
- data/config/locales/alchemy.en.yml +26 -8
- data/db/migrate/20250905140323_add_created_at_index_to_pictures_and_attachments.rb +14 -0
- data/lib/alchemy/configuration/base_option.rb +18 -5
- data/lib/alchemy/configuration/boolean_option.rb +2 -5
- data/lib/alchemy/configuration/collection_option.rb +69 -0
- data/lib/alchemy/configuration/configuration_option.rb +35 -0
- data/lib/alchemy/configuration/pathname_option.rb +12 -0
- data/lib/alchemy/configuration.rb +44 -6
- data/lib/alchemy/configurations/format_matchers.rb +1 -1
- data/lib/alchemy/configurations/importmap.rb +11 -0
- data/lib/alchemy/configurations/mailer.rb +2 -2
- data/lib/alchemy/configurations/main.rb +148 -3
- data/lib/alchemy/configurations/page_cache.rb +19 -0
- data/lib/alchemy/configurations/uploader.rb +2 -2
- data/lib/alchemy/deprecation.rb +1 -1
- data/lib/alchemy/engine.rb +43 -21
- data/lib/alchemy/install/tasks.rb +0 -12
- data/lib/alchemy/name_conversions.rb +6 -0
- data/lib/alchemy/tasks/tidy.rb +18 -0
- data/lib/alchemy/test_support/config_stubbing.rb +13 -4
- data/lib/alchemy/test_support/factories/language_factory.rb +8 -4
- data/lib/alchemy/test_support/factories/page_factory.rb +1 -0
- data/lib/alchemy/test_support/factories/picture_factory.rb +1 -0
- data/lib/alchemy/test_support/relatable_resource_examples.rb +58 -0
- data/lib/alchemy/tinymce.rb +0 -1
- data/lib/alchemy/version.rb +1 -1
- data/lib/alchemy.rb +18 -171
- data/lib/generators/alchemy/install/install_generator.rb +21 -10
- data/lib/generators/alchemy/install/templates/alchemy.rb.tt +88 -13
- data/lib/tasks/alchemy/assets.rake +1 -1
- data/lib/tasks/alchemy/tidy.rake +6 -0
- data/lib/tasks/alchemy/usage.rake +2 -0
- data/vendor/assets/stylesheets/tinymce/skins/content/dark/content.min.css +1 -0
- data/vendor/assets/stylesheets/tinymce/skins/content/default/content.min.css +1 -0
- data/vendor/assets/stylesheets/tinymce/skins/ui/oxide/skin.min.css +1 -0
- data/vendor/assets/stylesheets/tinymce/skins/ui/oxide-dark/content.min.css +1 -0
- data/vendor/assets/stylesheets/tinymce/skins/ui/oxide-dark/skin.min.css +1 -0
- data/vendor/javascript/clipboard.min.js +1 -1
- data/vendor/javascript/cropperjs.min.js +1 -1
- data/vendor/javascript/handlebars.min.js +3 -3
- data/vendor/javascript/jquery.min.js +1 -1
- data/vendor/javascript/select2.min.js +3 -3
- data/vendor/javascript/shoelace.min.js +92 -76
- data/vendor/javascript/sortable.min.js +2 -2
- data/vendor/javascript/tinymce.min.js +1 -1
- data/vendor/javascript/ungap-custom-elements.min.js +2 -2
- metadata +51 -36
- data/CHANGELOG.md +0 -2100
- data/CODE_OF_CONDUCT.md +0 -13
- data/CONTRIBUTING.md +0 -73
- data/Gemfile +0 -78
- data/Rakefile +0 -102
- data/SECURITY.md +0 -13
- data/alchemy_cms.gemspec +0 -97
- data/app/assets/builds/alchemy/custom-properties.css +0 -1
- data/app/helpers/alchemy/admin/elements_helper.rb +0 -25
- data/app/stylesheets/alchemy/custom-properties.css +0 -244
- data/bin/importmap +0 -4
- data/bin/rails +0 -9
- data/bin/rspec +0 -3
- data/bin/setup +0 -30
- data/bin/start +0 -17
- data/bun.lockb +0 -0
- data/bundles/remixicon.mjs +0 -153
- data/bundles/shoelace.js +0 -12
- data/bundles/tinymce.js +0 -22
- data/eslint.config.js +0 -18
- data/lib/alchemy/configuration/class_set_option.rb +0 -46
- data/lib/alchemy/configuration/integer_list_option.rb +0 -13
- data/lib/alchemy/configuration/list_option.rb +0 -22
- data/lib/alchemy/configuration/string_list_option.rb +0 -13
- data/lib/alchemy/upgrader/.keep +0 -0
- data/lib/alchemy/upgrader/tasks/.keep +0 -0
- data/rollup.config.mjs +0 -108
- data/vitest.config.js +0 -21
data/lib/alchemy/tasks/tidy.rb
CHANGED
|
@@ -73,6 +73,24 @@ module Alchemy
|
|
|
73
73
|
log "Deleted #{count} duplicate legacy URLs"
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
+
def remove_legacy_essence_tables
|
|
77
|
+
puts "\n## Removing legacy essence tables"
|
|
78
|
+
matching_tables = ActiveRecord::Base.connection.tables.select do |table|
|
|
79
|
+
table.start_with?("alchemy_essence_")
|
|
80
|
+
end
|
|
81
|
+
if matching_tables.length.zero?
|
|
82
|
+
log "No legacy essence tables found", :skip
|
|
83
|
+
nil
|
|
84
|
+
else
|
|
85
|
+
matching_tables.each do |table|
|
|
86
|
+
ActiveRecord::Base.connection.drop_table(table, if_exists: true)
|
|
87
|
+
print "."
|
|
88
|
+
end
|
|
89
|
+
puts "\n"
|
|
90
|
+
log "Deleted #{matching_tables.length} legacy essence tables"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
76
94
|
private
|
|
77
95
|
|
|
78
96
|
def destroy_orphaned_records(records, class_name)
|
|
@@ -13,11 +13,20 @@ module Alchemy
|
|
|
13
13
|
module ConfigStubbing
|
|
14
14
|
# Stub a key from the Alchemy config
|
|
15
15
|
#
|
|
16
|
-
# @param
|
|
17
|
-
# @param value [Object] The value you want to return instead of the original one
|
|
16
|
+
# @param hash [Hash] The keys you would like to stub along with their values
|
|
18
17
|
#
|
|
19
|
-
def stub_alchemy_config(
|
|
20
|
-
|
|
18
|
+
def stub_alchemy_config(hash)
|
|
19
|
+
stub_config(Alchemy.config, hash)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def stub_config(config, hash)
|
|
23
|
+
hash.each do |key, value|
|
|
24
|
+
if value.is_a?(Hash)
|
|
25
|
+
stub_config(config.send(key), value)
|
|
26
|
+
else
|
|
27
|
+
allow(config).to receive(key).and_return(value)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
21
30
|
end
|
|
22
31
|
end
|
|
23
32
|
end
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
FactoryBot.define do
|
|
4
4
|
factory :alchemy_language, class: "Alchemy::Language" do
|
|
5
5
|
name { "Your Language" }
|
|
6
|
-
|
|
6
|
+
language_code { "en" }
|
|
7
|
+
locale { ::I18n.default_locale }
|
|
7
8
|
default { true }
|
|
8
9
|
frontpage_name { "Intro" }
|
|
9
10
|
page_layout { Alchemy.config.default_language.page_layout }
|
|
@@ -14,20 +15,23 @@ FactoryBot.define do
|
|
|
14
15
|
|
|
15
16
|
trait :klingon do
|
|
16
17
|
name { "Klingon" }
|
|
17
|
-
|
|
18
|
+
language_code { "kl" }
|
|
19
|
+
locale { :kl }
|
|
18
20
|
frontpage_name { "Tuq" }
|
|
19
21
|
default { false }
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
trait :english do
|
|
23
25
|
name { "English" }
|
|
24
|
-
|
|
26
|
+
language_code { "en" }
|
|
27
|
+
locale { :en }
|
|
25
28
|
default { false }
|
|
26
29
|
end
|
|
27
30
|
|
|
28
31
|
trait :german do
|
|
29
32
|
name { "Deutsch" }
|
|
30
|
-
|
|
33
|
+
language_code { "de" }
|
|
34
|
+
locale { :de }
|
|
31
35
|
default { false }
|
|
32
36
|
end
|
|
33
37
|
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
RSpec.shared_examples_for "a relatable resource" do |args|
|
|
2
|
+
it { is_expected.to have_many(:related_ingredients) }
|
|
3
|
+
it { is_expected.to have_many(:elements).through(:related_ingredients) }
|
|
4
|
+
it { is_expected.to have_many(:pages).through(:elements) }
|
|
5
|
+
|
|
6
|
+
describe ".deletable" do
|
|
7
|
+
subject { described_class.deletable }
|
|
8
|
+
|
|
9
|
+
let!(:assigned_resource) { create(:"alchemy_#{args[:resource_name]}") }
|
|
10
|
+
let!(:unassigned_resource) { create(:"alchemy_#{args[:resource_name]}") }
|
|
11
|
+
let!(:ingredient1) { create(:"alchemy_ingredient_#{args[:ingredient_type]}", related_object: assigned_resource) }
|
|
12
|
+
let!(:ingredient2) { create(:"alchemy_ingredient_#{args[:ingredient_type]}", related_object: nil) }
|
|
13
|
+
|
|
14
|
+
it "should return all records that are not assigned to an ingredient" do
|
|
15
|
+
is_expected.to eq [unassigned_resource]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe "#related_ingredients" do
|
|
20
|
+
subject { resource.related_ingredients }
|
|
21
|
+
|
|
22
|
+
context "with other related resources with same id" do
|
|
23
|
+
let!(:resource) { create(:"alchemy_#{args[:resource_name]}") }
|
|
24
|
+
let!(:ingredient1) { create(:"alchemy_ingredient_#{args[:ingredient_type]}", related_object: resource) }
|
|
25
|
+
let!(:ingredient2) { create(:"alchemy_ingredient_#{args[:ingredient_type]}", related_object_type: "Event", related_object_id: resource.id) }
|
|
26
|
+
|
|
27
|
+
it "are not included" do
|
|
28
|
+
is_expected.to eq [ingredient1]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
context "with other related resources with same type" do
|
|
33
|
+
let!(:resource) { create(:"alchemy_#{args[:resource_name]}") }
|
|
34
|
+
let!(:ingredient1) { create(:"alchemy_ingredient_#{args[:ingredient_type]}", related_object: resource) }
|
|
35
|
+
let!(:ingredient2) { create(:"alchemy_ingredient_#{args[:ingredient_type]}", related_object_type: described_class) }
|
|
36
|
+
|
|
37
|
+
it "are not included" do
|
|
38
|
+
is_expected.to eq [ingredient1]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe "#deletable?" do
|
|
44
|
+
let(:resource) { create(:"alchemy_#{args[:resource_name]}") }
|
|
45
|
+
|
|
46
|
+
subject { resource.deletable? }
|
|
47
|
+
|
|
48
|
+
context "if related to ingredient" do
|
|
49
|
+
let!(:ingredient) { create(:"alchemy_ingredient_#{args[:ingredient_type]}", related_object: resource) }
|
|
50
|
+
|
|
51
|
+
it { is_expected.to be(false) }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context "if not related to ingredient" do
|
|
55
|
+
it { is_expected.to be(true) }
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
data/lib/alchemy/tinymce.rb
CHANGED
data/lib/alchemy/version.rb
CHANGED
data/lib/alchemy.rb
CHANGED
|
@@ -15,6 +15,8 @@ module Alchemy
|
|
|
15
15
|
singleton_class.attr_accessor :importmap
|
|
16
16
|
self.importmap = Importmap::Map.new
|
|
17
17
|
|
|
18
|
+
mattr_accessor :storage_adapter
|
|
19
|
+
|
|
18
20
|
class << self
|
|
19
21
|
def config
|
|
20
22
|
@_config ||= Alchemy::Configurations::Main.new
|
|
@@ -33,181 +35,26 @@ module Alchemy
|
|
|
33
35
|
end
|
|
34
36
|
deprecate enable_searchable: enable_searchable_deprecation_msg, deprecator: Alchemy::Deprecation
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
# admin UI.
|
|
41
|
-
#
|
|
42
|
-
# == Example
|
|
43
|
-
#
|
|
44
|
-
# # lib/acme/preview_source.rb
|
|
45
|
-
# class Acme::PreviewSource < Alchemy::Admin::PreviewUrl
|
|
46
|
-
# def url_for(page)
|
|
47
|
-
# if page.site.name == "Next"
|
|
48
|
-
# "https://user:#{ENV['PREVIEW_HTTP_PASS']}@next.acme.com"
|
|
49
|
-
# else
|
|
50
|
-
# "https://www.acme.com"
|
|
51
|
-
# end
|
|
52
|
-
# end
|
|
53
|
-
# end
|
|
54
|
-
#
|
|
55
|
-
# # config/initializers/alchemy.rb
|
|
56
|
-
# require "acme/preview_source"
|
|
57
|
-
# Alchemy.preview_sources << Acme::PreviewSource
|
|
58
|
-
#
|
|
59
|
-
# # config/locales/de.yml
|
|
60
|
-
# de:
|
|
61
|
-
# activemodel:
|
|
62
|
-
# models:
|
|
63
|
-
# acme/preview_source: Acme Vorschau
|
|
64
|
-
#
|
|
65
|
-
def preview_sources
|
|
66
|
-
@_preview_sources ||= Set.new << Alchemy::Admin::PreviewUrl
|
|
67
|
-
end
|
|
38
|
+
delegate :preview_sources, to: :config
|
|
39
|
+
delegate :preview_sources=, to: :config
|
|
40
|
+
deprecate preview_sources: "Use `Alchemy.config.preview_sources` instead.", deprecator: Alchemy::Deprecation
|
|
41
|
+
deprecate :preview_sources= => "Use `Alchemy.config.preview_sources=` instead.", :deprecator => Alchemy::Deprecation
|
|
68
42
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
43
|
+
delegate :admin_js_imports, to: :config
|
|
44
|
+
delegate :admin_js_imports=, to: :config
|
|
45
|
+
deprecate admin_js_imports: "Use `Alchemy.config.admin_js_imports` instead", deprecator: Alchemy::Deprecation
|
|
46
|
+
deprecate :admin_js_imports= => "Use `Alchemy.config.admin_js_imports=` instead", :deprecator => Alchemy::Deprecation
|
|
72
47
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
# Be sure to also pin the modules with +Alchemy.importmap+.
|
|
76
|
-
#
|
|
77
|
-
# == Example
|
|
78
|
-
#
|
|
79
|
-
# Alchemy.importmap.pin "flatpickr/de",
|
|
80
|
-
# to: "https://ga.jspm.io/npm:flatpickr@4.6.13/dist/l10n/de.js"
|
|
81
|
-
#
|
|
82
|
-
# Alchemy.admin_js_imports << "flatpickr/de"
|
|
83
|
-
#
|
|
84
|
-
def admin_js_imports
|
|
85
|
-
@_admin_js_imports ||= Set.new
|
|
86
|
-
end
|
|
48
|
+
delegate :admin_importmaps, to: :config
|
|
49
|
+
deprecate admin_importmaps: "Use Alchemy.config.admin_importmaps instead", deprecator: Alchemy::Deprecation
|
|
87
50
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# Additional importmaps to be included in the Alchemy admin UI
|
|
93
|
-
#
|
|
94
|
-
# Be sure to also pin modules with +Alchemy.importmap+.
|
|
95
|
-
#
|
|
96
|
-
# == Example
|
|
97
|
-
#
|
|
98
|
-
# # config/alchemy/importmap.rb
|
|
99
|
-
# Alchemy.importmap.pin "alchemy_solidus", to: "alchemy_solidus.js", preload: true
|
|
100
|
-
# Alchemy.importmap.pin_all_from Alchemy::Solidus::Engine.root.join("app/javascript/alchemy_solidus"),
|
|
101
|
-
# under: "alchemy_solidus",
|
|
102
|
-
# preload: true
|
|
103
|
-
#
|
|
104
|
-
# # lib/alchemy/solidus/engine.rb
|
|
105
|
-
# initializer "alchemy_solidus.assets", before: "alchemy.importmap" do |app|
|
|
106
|
-
# Alchemy.admin_importmaps.add({
|
|
107
|
-
# importmap_path: root.join("config/importmap.rb"),
|
|
108
|
-
# source_paths: [
|
|
109
|
-
# root.join("app/javascript")
|
|
110
|
-
# ],
|
|
111
|
-
# name: "alchemy_solidus"
|
|
112
|
-
# })
|
|
113
|
-
# app.config.assets.precompile << "alchemy_solidus/manifest.js"
|
|
114
|
-
# end
|
|
115
|
-
#
|
|
116
|
-
# @return [Set<Hash>]
|
|
117
|
-
def admin_importmaps
|
|
118
|
-
@_admin_importmaps ||= Set.new([{
|
|
119
|
-
importmap_path: Engine.root.join("config/importmap.rb"),
|
|
120
|
-
source_paths: [
|
|
121
|
-
Engine.root.join("app/javascript"),
|
|
122
|
-
Engine.root.join("vendor/javascript")
|
|
123
|
-
],
|
|
124
|
-
name: "alchemy_admin"
|
|
125
|
-
}])
|
|
126
|
-
end
|
|
51
|
+
delegate :admin_stylesheets, to: :config
|
|
52
|
+
deprecate admin_stylesheets: "Use Alchemy.config.admin_stylesheets instead", deprecator: Alchemy::Deprecation
|
|
127
53
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
# == Example
|
|
131
|
-
#
|
|
132
|
-
# # lib/alchemy/devise/engine.rb
|
|
133
|
-
# initializer "alchemy.devise.stylesheets", before: "alchemy.admin_stylesheets" do
|
|
134
|
-
# Alchemy.admin_stylesheets << "alchemy/devise/admin.css"
|
|
135
|
-
# end
|
|
136
|
-
#
|
|
137
|
-
# @return [Set<String>]
|
|
138
|
-
def admin_stylesheets
|
|
139
|
-
@_admin_stylesheets ||= Set.new(["alchemy/admin/custom.css"])
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# Define page publish targets
|
|
143
|
-
#
|
|
144
|
-
# A publish target is a ActiveJob that gets performed
|
|
145
|
-
# whenever a user clicks the publish page button.
|
|
146
|
-
#
|
|
147
|
-
# Use this to trigger deployment hooks of external
|
|
148
|
-
# services in an asychronous way.
|
|
149
|
-
#
|
|
150
|
-
# == Example
|
|
151
|
-
#
|
|
152
|
-
# # app/jobs/publish_job.rb
|
|
153
|
-
# class PublishJob < ApplicationJob
|
|
154
|
-
# def perform(page)
|
|
155
|
-
# RestClient.post(ENV['BUILD_HOOK_URL'])
|
|
156
|
-
# end
|
|
157
|
-
# end
|
|
158
|
-
#
|
|
159
|
-
# # config/initializers/alchemy.rb
|
|
160
|
-
# Alchemy.publish_targets << PublishJob
|
|
161
|
-
#
|
|
162
|
-
def publish_targets
|
|
163
|
-
@_publish_targets ||= Set.new
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
# Configure tabs in the link dialog
|
|
167
|
-
#
|
|
168
|
-
# With this configuration that tabs in the link dialog can be extended
|
|
169
|
-
# without overwriting or defacing the Admin Interface.
|
|
170
|
-
#
|
|
171
|
-
# == Example
|
|
172
|
-
#
|
|
173
|
-
# # components/acme/link_tab.rb
|
|
174
|
-
# module Acme
|
|
175
|
-
# class LinkTab < ::Alchemy::Admin::LinkDialog::BaseTab
|
|
176
|
-
# def title
|
|
177
|
-
# "Awesome Tab Title"
|
|
178
|
-
# end
|
|
179
|
-
#
|
|
180
|
-
# def name
|
|
181
|
-
# :unique_name
|
|
182
|
-
# end
|
|
183
|
-
#
|
|
184
|
-
# def fields
|
|
185
|
-
# [ title_input, target_select ]
|
|
186
|
-
# end
|
|
187
|
-
# end
|
|
188
|
-
# end
|
|
189
|
-
#
|
|
190
|
-
# # config/initializers/alchemy.rb
|
|
191
|
-
# Alchemy.link_dialog_tabs << Acme::LinkTab
|
|
192
|
-
#
|
|
193
|
-
def link_dialog_tabs
|
|
194
|
-
@_link_dialog_tabs ||= Set.new([
|
|
195
|
-
Alchemy::Admin::LinkDialog::InternalTab,
|
|
196
|
-
Alchemy::Admin::LinkDialog::AnchorTab,
|
|
197
|
-
Alchemy::Admin::LinkDialog::ExternalTab,
|
|
198
|
-
Alchemy::Admin::LinkDialog::FileTab
|
|
199
|
-
])
|
|
200
|
-
end
|
|
201
|
-
end
|
|
54
|
+
delegate :publish_targets, to: :config
|
|
55
|
+
deprecate publish_targets: "Use Alchemy.config.publish_targets instead", deprecator: Alchemy::Deprecation
|
|
202
56
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
# Chose between 'active_storage' (default) or 'dragonfly' (legacy)
|
|
206
|
-
#
|
|
207
|
-
# Can be set via 'ALCHEMY_STORAGE_ADAPTER' env var.
|
|
208
|
-
def self.storage_adapter
|
|
209
|
-
@_storage_adapter ||= Alchemy::StorageAdapter.new(
|
|
210
|
-
ENV.fetch("ALCHEMY_STORAGE_ADAPTER", Alchemy.config.storage_adapter)
|
|
211
|
-
)
|
|
57
|
+
delegate :link_dialog_tabs, to: :config
|
|
58
|
+
deprecate link_dialog_tabs: "Use Alchemy.config.link_dialog_tabs instead", deprecator: Alchemy::Deprecation
|
|
212
59
|
end
|
|
213
60
|
end
|
|
@@ -60,7 +60,17 @@ module Alchemy
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
def copy_config_rb
|
|
63
|
-
@
|
|
63
|
+
@default_language = get_primary_language(
|
|
64
|
+
code: options[:default_language_code],
|
|
65
|
+
name: options[:default_language_name],
|
|
66
|
+
auto_accept: options[:auto_accept]
|
|
67
|
+
)
|
|
68
|
+
@default_config = Alchemy::Configurations::Main.new(
|
|
69
|
+
default_language: {
|
|
70
|
+
name: @default_language[:name],
|
|
71
|
+
code: @default_language[:code]
|
|
72
|
+
}
|
|
73
|
+
)
|
|
64
74
|
template "#{__dir__}/templates/alchemy.rb.tt", app_config_path.join("initializers", "alchemy.rb")
|
|
65
75
|
end
|
|
66
76
|
|
|
@@ -89,15 +99,6 @@ module Alchemy
|
|
|
89
99
|
rake "gutentag:install:migrations"
|
|
90
100
|
end
|
|
91
101
|
|
|
92
|
-
def set_primary_language
|
|
93
|
-
header
|
|
94
|
-
install_tasks.set_primary_language(
|
|
95
|
-
code: options[:default_language_code],
|
|
96
|
-
name: options[:default_language_name],
|
|
97
|
-
auto_accept: options[:auto_accept]
|
|
98
|
-
)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
102
|
def setup_database
|
|
102
103
|
rake("db:create", abort_on_failure: true) unless options[:skip_db_create]
|
|
103
104
|
# We can't invoke this rake task, because Rails will use wrong engine names otherwise
|
|
@@ -118,6 +119,16 @@ module Alchemy
|
|
|
118
119
|
|
|
119
120
|
private
|
|
120
121
|
|
|
122
|
+
def get_primary_language(code: "en", name: "English", auto_accept: false)
|
|
123
|
+
unless options[:auto_accept]
|
|
124
|
+
code = ask("- What is the language code of your site's primary language?", default: code)
|
|
125
|
+
end
|
|
126
|
+
unless options[:auto_accept]
|
|
127
|
+
name = ask("- What is the name of your site's primary language?", default: name)
|
|
128
|
+
end
|
|
129
|
+
{code:, name:}
|
|
130
|
+
end
|
|
131
|
+
|
|
121
132
|
def header
|
|
122
133
|
return if options[:auto_accept]
|
|
123
134
|
|
|
@@ -97,12 +97,12 @@ Alchemy.configure do |config|
|
|
|
97
97
|
# end
|
|
98
98
|
|
|
99
99
|
# This is the default language when seeding.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
100
|
+
config.default_language.tap do |default_language|
|
|
101
|
+
default_language.code = <%= @default_config.default_language.code.inspect %>
|
|
102
|
+
default_language.name = <%= @default_config.default_language.name.inspect %>
|
|
103
|
+
# default_language.page_layout = <%= @default_config.default_language.page_layout.inspect %>
|
|
104
|
+
# default_language.frontpage_name = <%= @default_config.default_language.frontpage_name.inspect %>
|
|
105
|
+
end
|
|
106
106
|
|
|
107
107
|
# === Mailer Settings:
|
|
108
108
|
#
|
|
@@ -137,8 +137,8 @@ Alchemy.configure do |config|
|
|
|
137
137
|
# mailer.mail_from = <%= @default_config.mailer.mail_from.inspect %>
|
|
138
138
|
# mailer.mail_to = <%= @default_config.mailer.mail_to.inspect %>
|
|
139
139
|
# mailer.subject = <%= @default_config.mailer.subject.inspect %>
|
|
140
|
-
# mailer.fields = <%= @default_config.mailer.fields.
|
|
141
|
-
# mailer.validate_fields = <%= @default_config.mailer.validate_fields.
|
|
140
|
+
# mailer.fields = <%= @default_config.mailer.fields.map(&:to_s) %>
|
|
141
|
+
# mailer.validate_fields = <%= @default_config.mailer.validate_fields.map(&:to_s) %>
|
|
142
142
|
# end
|
|
143
143
|
|
|
144
144
|
# === User roles
|
|
@@ -157,7 +157,7 @@ Alchemy.configure do |config|
|
|
|
157
157
|
# user_roles:
|
|
158
158
|
# rolename: Name of the role
|
|
159
159
|
#
|
|
160
|
-
# config.user_roles = <%= @default_config.user_roles.
|
|
160
|
+
# config.user_roles = <%= @default_config.user_roles.map(&:to_s) %>
|
|
161
161
|
|
|
162
162
|
# === Uploader Settings
|
|
163
163
|
#
|
|
@@ -170,8 +170,8 @@ Alchemy.configure do |config|
|
|
|
170
170
|
# uploader.upload_limit = <%= @default_config.uploader.upload_limit.inspect %>
|
|
171
171
|
# uploader.file_size_limit = <%= @default_config.uploader.file_size_limit.inspect %>
|
|
172
172
|
# uploader.allowed_filetypes.tap do |file_types|
|
|
173
|
-
# file_types.alchemy_attachments = <%= @default_config.uploader.allowed_filetypes.alchemy_attachments.
|
|
174
|
-
# file_types.alchemy_pictures = <%= @default_config.uploader.allowed_filetypes.alchemy_pictures.
|
|
173
|
+
# file_types.alchemy_attachments = <%= @default_config.uploader.allowed_filetypes.alchemy_attachments.map(&:to_s) %>
|
|
174
|
+
# file_types.alchemy_pictures = <%= @default_config.uploader.allowed_filetypes.alchemy_pictures.map(&:to_s) %>
|
|
175
175
|
# end
|
|
176
176
|
# end
|
|
177
177
|
|
|
@@ -186,11 +186,86 @@ Alchemy.configure do |config|
|
|
|
186
186
|
#
|
|
187
187
|
# jQuery(a[data-link-target="overlay"]).dialog();
|
|
188
188
|
#
|
|
189
|
-
# config.link_target_options = <%= @default_config.link_target_options.
|
|
189
|
+
# config.link_target_options = <%= @default_config.link_target_options.map(&:to_s) %>
|
|
190
|
+
|
|
191
|
+
# === Format matchers
|
|
192
|
+
#
|
|
193
|
+
# Named aliases for regular expressions that can be used in various places.
|
|
194
|
+
# The most common use case is the format validation of ingredients, or attribute validations of your individual models.
|
|
195
|
+
#
|
|
196
|
+
# == Example:
|
|
197
|
+
#
|
|
198
|
+
# validates_format_of :url, with: Alchemy.config.format_matchers.url
|
|
199
|
+
#
|
|
200
|
+
# config.format_matchers.tap do |format|
|
|
201
|
+
# format.email = <%= @default_config.format_matchers.email.inspect %>
|
|
202
|
+
# format.url = <%= @default_config.format_matchers.url.inspect %>
|
|
203
|
+
# format.link_url = <%= @default_config.format_matchers.link_url.inspect %>
|
|
204
|
+
# end
|
|
190
205
|
|
|
191
206
|
# The layout used for rendering the +alchemy/admin/pages#show+ action.
|
|
192
207
|
# config.admin_page_preview_layout = <%= @default_config.admin_page_preview_layout.inspect %>
|
|
193
208
|
|
|
194
209
|
# The sizes for the preview size select in the page editor.
|
|
195
|
-
# config.page_preview_sizes = <%= @default_config.page_preview_sizes.
|
|
210
|
+
# config.page_preview_sizes = <%= @default_config.page_preview_sizes.map(&:to_s) %>
|
|
211
|
+
|
|
212
|
+
# Enable full text search configuration
|
|
213
|
+
#
|
|
214
|
+
# It enables a searchable checkbox in the page form to toggle
|
|
215
|
+
# the searchable field. These information can used in a search
|
|
216
|
+
# plugin (e.g. https://github.com/AlchemyCMS/alchemy-pg_search).
|
|
217
|
+
#
|
|
218
|
+
# == Example
|
|
219
|
+
#
|
|
220
|
+
# # config/initializers/alchemy.rb
|
|
221
|
+
# Alchemy.config.page_searchable_checkbox = true
|
|
222
|
+
#
|
|
223
|
+
# config.show_page_searchable_checkbox = <%= @default_config.show_page_searchable_checkbox.inspect %>
|
|
224
|
+
|
|
225
|
+
# The storage adapter for Pictures and Attachments
|
|
226
|
+
#
|
|
227
|
+
config.storage_adapter = <%= @default_config.storage_adapter.inspect %>
|
|
228
|
+
|
|
229
|
+
# Additional JS modules to be imported in the Alchemy admin UI
|
|
230
|
+
#
|
|
231
|
+
# Be sure to also pin the modules with +Alchemy.importmap+.
|
|
232
|
+
#
|
|
233
|
+
# == Example
|
|
234
|
+
#
|
|
235
|
+
# Alchemy.importmap.pin "flatpickr/de",
|
|
236
|
+
# to: "https://ga.jspm.io/npm:flatpickr@4.6.13/dist/l10n/de.js"
|
|
237
|
+
#
|
|
238
|
+
# config.admin_js_imports << "flatpickr/de"
|
|
239
|
+
|
|
240
|
+
# Additional importmaps to be included in the Alchemy admin UI
|
|
241
|
+
#
|
|
242
|
+
# Be sure to also pin modules with +Alchemy.importmap+.
|
|
243
|
+
#
|
|
244
|
+
# config.admin_importmaps.add(
|
|
245
|
+
# importmap_path: root.join("config/importmap.rb"),
|
|
246
|
+
# source_paths: [
|
|
247
|
+
# root.join("app/javascript")
|
|
248
|
+
# ],
|
|
249
|
+
# name: "admin_extension"
|
|
250
|
+
# )
|
|
251
|
+
|
|
252
|
+
# Additional stylesheets to be included in the Alchemy admin UI
|
|
253
|
+
# config.admin_stylesheets.add("my_app/admin_extension")
|
|
254
|
+
|
|
255
|
+
# Define page publish targets
|
|
256
|
+
#
|
|
257
|
+
# A publish target is a ActiveJob that gets performed
|
|
258
|
+
# whenever a user clicks the publish page button.
|
|
259
|
+
#
|
|
260
|
+
# Use this to trigger deployment hooks of external
|
|
261
|
+
# services in an asychronous way.
|
|
262
|
+
#
|
|
263
|
+
# config.publish_targets << "MyPublishJob"
|
|
264
|
+
|
|
265
|
+
# Configure tabs in the link dialog
|
|
266
|
+
#
|
|
267
|
+
# With this configuration that tabs in the link dialog can be extended
|
|
268
|
+
# without overwriting or defacing the Admin Interface.
|
|
269
|
+
#
|
|
270
|
+
# config.link_dialog_tabs << "Acme::LinkTab"
|
|
196
271
|
end
|
|
@@ -6,7 +6,7 @@ if Rake::Task.task_defined?("assets:precompile") && defined?(Propshaft)
|
|
|
6
6
|
manifest.select { |k| k.include?("tinymce/") }.each do |k, v|
|
|
7
7
|
Propshaft.logger.info "Copying #{v} to #{k}"
|
|
8
8
|
FileUtils.cp(
|
|
9
|
-
assets_path.join(v),
|
|
9
|
+
assets_path.join(v.dig("digested_path") || v),
|
|
10
10
|
assets_path.join(k)
|
|
11
11
|
)
|
|
12
12
|
end
|
data/lib/tasks/alchemy/tidy.rake
CHANGED
|
@@ -10,6 +10,7 @@ namespace :alchemy do
|
|
|
10
10
|
Rake::Task["alchemy:tidy:remove_orphaned_records"].invoke
|
|
11
11
|
Rake::Task["alchemy:tidy:remove_trashed_elements"].invoke
|
|
12
12
|
Rake::Task["alchemy:tidy:remove_duplicate_legacy_urls"].invoke
|
|
13
|
+
Rake::Task["alchemy:tidy:remove_legacy_essence_tables"].invoke
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
desc "Fixes element positions."
|
|
@@ -37,6 +38,11 @@ namespace :alchemy do
|
|
|
37
38
|
Alchemy::Tidy.remove_duplicate_legacy_urls
|
|
38
39
|
end
|
|
39
40
|
|
|
41
|
+
desc "Remove all legacy essence tables"
|
|
42
|
+
task remove_legacy_essence_tables: [:environment] do
|
|
43
|
+
Alchemy::Tidy.remove_legacy_essence_tables
|
|
44
|
+
end
|
|
45
|
+
|
|
40
46
|
desc "List Alchemy elements usage"
|
|
41
47
|
task elements_usage: :environment do
|
|
42
48
|
puts "\n"
|
|
@@ -7,6 +7,7 @@ namespace :alchemy do
|
|
|
7
7
|
desc "List Alchemy elements usage"
|
|
8
8
|
task page_usage: :environment do
|
|
9
9
|
include ActionView::Helpers::NumberHelper
|
|
10
|
+
|
|
10
11
|
puts "\n Alchemy pages usage"
|
|
11
12
|
results = Alchemy::Tasks::Usage.pages_count_by_type
|
|
12
13
|
if results.any?
|
|
@@ -24,6 +25,7 @@ namespace :alchemy do
|
|
|
24
25
|
desc "List Alchemy elements usage"
|
|
25
26
|
task element_usage: :environment do
|
|
26
27
|
include ActionView::Helpers::NumberHelper
|
|
28
|
+
|
|
27
29
|
puts "\n Alchemy elements usage"
|
|
28
30
|
results = Alchemy::Tasks::Usage.elements_count_by_name
|
|
29
31
|
if results.any?
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
body{background-color:#222f3e;color:#fff;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}
|