plum-cms 0.1.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 +7 -0
- data/CHANGELOG.md +20 -0
- data/LICENSE.txt +21 -0
- data/README.md +252 -0
- data/app/assets/builds/tailwind.css +2 -0
- data/app/assets/images/plum-mark.svg +7 -0
- data/app/assets/images/table-needs-logo.svg +83 -0
- data/app/assets/javascripts/plum/application.js +15 -0
- data/app/assets/stylesheets/application.css +10 -0
- data/app/assets/stylesheets/plum/control_panel.css +2 -0
- data/app/assets/tailwind/application.css +47 -0
- data/app/controllers/plum/application_controller.rb +34 -0
- data/app/controllers/plum/cp/assets_controller.rb +84 -0
- data/app/controllers/plum/cp/base_controller.rb +45 -0
- data/app/controllers/plum/cp/content_types_controller.rb +59 -0
- data/app/controllers/plum/cp/dashboard_controller.rb +10 -0
- data/app/controllers/plum/cp/entries_controller.rb +240 -0
- data/app/controllers/plum/cp/form_definitions_controller.rb +105 -0
- data/app/controllers/plum/cp/form_submissions_controller.rb +26 -0
- data/app/controllers/plum/cp/globals_controller.rb +84 -0
- data/app/controllers/plum/cp/nav_items_controller.rb +68 -0
- data/app/controllers/plum/cp/nav_menus_controller.rb +56 -0
- data/app/controllers/plum/cp/site_settings_controller.rb +87 -0
- data/app/controllers/plum/cp/taxonomies_controller.rb +56 -0
- data/app/controllers/plum/cp/terms_controller.rb +55 -0
- data/app/controllers/plum/cp/theme_previews_controller.rb +27 -0
- data/app/controllers/plum/cp/themes_controller.rb +98 -0
- data/app/controllers/plum/form_submissions_controller.rb +44 -0
- data/app/controllers/plum/pages_controller.rb +161 -0
- data/app/controllers/plum/sessions_controller.rb +25 -0
- data/app/controllers/plum/theme_assets_controller.rb +14 -0
- data/app/helpers/application_helper.rb +2 -0
- data/app/helpers/markdown_helper.rb +21 -0
- data/app/helpers/plum/cp/assets_helper.rb +21 -0
- data/app/helpers/plum/cp/theme_settings_helper.rb +26 -0
- data/app/javascript/application.js +18 -0
- data/app/javascript/controllers/application.js +9 -0
- data/app/javascript/controllers/index.js +4 -0
- data/app/javascript/controllers/plum/blocks_editor_controller.js +275 -0
- data/app/javascript/controllers/plum/blueprint_controller.js +120 -0
- data/app/javascript/controllers/plum/form_fields_controller.js +84 -0
- data/app/javascript/controllers/plum/image_picker_controller.js +143 -0
- data/app/javascript/controllers/plum/theme_settings_controller.js +17 -0
- data/app/models/plum/application_record.rb +5 -0
- data/app/models/plum/asset.rb +69 -0
- data/app/models/plum/content_type.rb +35 -0
- data/app/models/plum/entry.rb +67 -0
- data/app/models/plum/entry_term.rb +8 -0
- data/app/models/plum/form_definition.rb +68 -0
- data/app/models/plum/form_submission.rb +76 -0
- data/app/models/plum/global.rb +24 -0
- data/app/models/plum/nav_item.rb +58 -0
- data/app/models/plum/nav_menu.rb +24 -0
- data/app/models/plum/site.rb +112 -0
- data/app/models/plum/site_scoped.rb +17 -0
- data/app/models/plum/site_setting.rb +35 -0
- data/app/models/plum/taxonomy.rb +24 -0
- data/app/models/plum/term.rb +23 -0
- data/app/models/plum/user.rb +16 -0
- data/app/services/plum/base_blocks.rb +161 -0
- data/app/services/plum/block_editor_config.rb +65 -0
- data/app/services/plum/block_library.rb +31 -0
- data/app/services/plum/builder_renderer.rb +63 -0
- data/app/services/plum/field_expander.rb +78 -0
- data/app/services/plum/form_renderer.rb +110 -0
- data/app/services/plum/liquid_context.rb +335 -0
- data/app/services/plum/liquid_filters.rb +58 -0
- data/app/services/plum/liquid_renderer.rb +49 -0
- data/app/services/plum/theme.rb +160 -0
- data/app/services/plum/theme_asset_path.rb +31 -0
- data/app/services/plum/theme_package_installer.rb +287 -0
- data/app/services/plum/theme_registry.rb +63 -0
- data/app/services/plum/theme_resolver.rb +55 -0
- data/app/services/plum/theme_settings_params.rb +54 -0
- data/app/themes/bagel-boy/assets/screenshot.svg +92 -0
- data/app/themes/bagel-boy/assets/theme.css +184 -0
- data/app/themes/bagel-boy/blocks/hours.liquid +4 -0
- data/app/themes/bagel-boy/blocks/menu_item.liquid +7 -0
- data/app/themes/bagel-boy/layouts/base.liquid +64 -0
- data/app/themes/bagel-boy/templates/collections/posts.liquid +32 -0
- data/app/themes/bagel-boy/templates/entries/_default.liquid +13 -0
- data/app/themes/bagel-boy/templates/entries/landing.liquid +4 -0
- data/app/themes/bagel-boy/templates/entries/pages.liquid +18 -0
- data/app/themes/bagel-boy/templates/entries/posts.liquid +8 -0
- data/app/themes/bagel-boy/templates/index.liquid +10 -0
- data/app/themes/bagel-boy/templates/search.liquid +28 -0
- data/app/themes/bagel-boy/theme.yml +47 -0
- data/app/themes/bagel-shop/assets/screenshot.svg +28 -0
- data/app/themes/bagel-shop/assets/theme.css +7 -0
- data/app/themes/bagel-shop/layouts/base.liquid +507 -0
- data/app/themes/bagel-shop/templates/entries/_default.liquid +15 -0
- data/app/themes/bagel-shop/templates/entries/pages.liquid +12 -0
- data/app/themes/bagel-shop/templates/entries/posts.liquid +19 -0
- data/app/themes/bagel-shop/templates/index.liquid +55 -0
- data/app/themes/bagel-shop/theme.yml +30 -0
- data/app/themes/default/assets/screenshot.svg +24 -0
- data/app/themes/default/assets/theme.css +89 -0
- data/app/themes/default/layouts/base.liquid +117 -0
- data/app/themes/default/templates/collections/_default.liquid +16 -0
- data/app/themes/default/templates/collections/posts.liquid +27 -0
- data/app/themes/default/templates/entries/_default.liquid +26 -0
- data/app/themes/default/templates/entries/landing.liquid +5 -0
- data/app/themes/default/templates/entries/pages.liquid +17 -0
- data/app/themes/default/templates/entries/posts.liquid +20 -0
- data/app/themes/default/templates/index.liquid +22 -0
- data/app/themes/default/templates/search.liquid +28 -0
- data/app/themes/default/templates/taxonomies/_default.liquid +25 -0
- data/app/themes/default/templates/taxonomies/_default_index.liquid +14 -0
- data/app/themes/default/theme.yml +23 -0
- data/app/views/layouts/plum/cp.html.erb +138 -0
- data/app/views/layouts/plum/session.html.erb +43 -0
- data/app/views/plum/cp/assets/_form.html.erb +44 -0
- data/app/views/plum/cp/assets/edit.html.erb +14 -0
- data/app/views/plum/cp/assets/index.html.erb +52 -0
- data/app/views/plum/cp/assets/new.html.erb +9 -0
- data/app/views/plum/cp/content_types/_form.html.erb +113 -0
- data/app/views/plum/cp/content_types/edit.html.erb +8 -0
- data/app/views/plum/cp/content_types/index.html.erb +48 -0
- data/app/views/plum/cp/content_types/new.html.erb +5 -0
- data/app/views/plum/cp/content_types/show.html.erb +59 -0
- data/app/views/plum/cp/dashboard/show.html.erb +50 -0
- data/app/views/plum/cp/entries/_form.html.erb +196 -0
- data/app/views/plum/cp/entries/edit.html.erb +9 -0
- data/app/views/plum/cp/entries/index.html.erb +51 -0
- data/app/views/plum/cp/entries/new.html.erb +5 -0
- data/app/views/plum/cp/form_definitions/_form.html.erb +90 -0
- data/app/views/plum/cp/form_definitions/edit.html.erb +11 -0
- data/app/views/plum/cp/form_definitions/index.html.erb +43 -0
- data/app/views/plum/cp/form_definitions/new.html.erb +5 -0
- data/app/views/plum/cp/form_definitions/show.html.erb +70 -0
- data/app/views/plum/cp/form_submissions/show.html.erb +20 -0
- data/app/views/plum/cp/globals/_form.html.erb +44 -0
- data/app/views/plum/cp/globals/edit.html.erb +11 -0
- data/app/views/plum/cp/globals/index.html.erb +41 -0
- data/app/views/plum/cp/globals/new.html.erb +5 -0
- data/app/views/plum/cp/globals/show.html.erb +14 -0
- data/app/views/plum/cp/nav_items/_form.html.erb +56 -0
- data/app/views/plum/cp/nav_items/edit.html.erb +11 -0
- data/app/views/plum/cp/nav_items/new.html.erb +6 -0
- data/app/views/plum/cp/nav_menus/_form.html.erb +33 -0
- data/app/views/plum/cp/nav_menus/_nav_item.html.erb +24 -0
- data/app/views/plum/cp/nav_menus/edit.html.erb +11 -0
- data/app/views/plum/cp/nav_menus/index.html.erb +41 -0
- data/app/views/plum/cp/nav_menus/new.html.erb +5 -0
- data/app/views/plum/cp/nav_menus/show.html.erb +24 -0
- data/app/views/plum/cp/shared/_icon.html.erb +39 -0
- data/app/views/plum/cp/shared/_image_picker.html.erb +38 -0
- data/app/views/plum/cp/site_settings/edit.html.erb +145 -0
- data/app/views/plum/cp/site_settings/show.html.erb +62 -0
- data/app/views/plum/cp/taxonomies/_form.html.erb +38 -0
- data/app/views/plum/cp/taxonomies/edit.html.erb +2 -0
- data/app/views/plum/cp/taxonomies/index.html.erb +38 -0
- data/app/views/plum/cp/taxonomies/new.html.erb +2 -0
- data/app/views/plum/cp/taxonomies/show.html.erb +46 -0
- data/app/views/plum/cp/terms/_form.html.erb +30 -0
- data/app/views/plum/cp/terms/edit.html.erb +2 -0
- data/app/views/plum/cp/terms/new.html.erb +2 -0
- data/app/views/plum/cp/themes/index.html.erb +160 -0
- data/app/views/plum/form_mailer/submission_notification.html.erb +13 -0
- data/app/views/plum/form_mailer/submission_notification.text.erb +7 -0
- data/app/views/plum/sessions/new.html.erb +20 -0
- data/compat/plum-cms.rb +1 -0
- data/config/locales/en.yml +31 -0
- data/config/plum_importmap.rb +4 -0
- data/config/plum_routes.rb +34 -0
- data/db/engine_migrate/20260101000001_create_plum_tables.rb +154 -0
- data/lib/generators/plum/install/install_generator.rb +54 -0
- data/lib/generators/plum/install/templates/plum_initializer.rb +37 -0
- data/lib/plum/configuration.rb +88 -0
- data/lib/plum/content_source.rb +45 -0
- data/lib/plum/content_source_context.rb +30 -0
- data/lib/plum/content_source_registry.rb +120 -0
- data/lib/plum/engine.rb +30 -0
- data/lib/plum/liquid_tags/form_tag.rb +17 -0
- data/lib/plum/version.rb +7 -0
- data/lib/plum.rb +11 -0
- data/vendor/javascript/lexxy.js +11859 -0
- metadata +405 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Plum
|
|
2
|
+
class ContentSourceContext
|
|
3
|
+
attr_reader :controller, :site
|
|
4
|
+
|
|
5
|
+
def initialize(controller:, site:)
|
|
6
|
+
@controller = controller
|
|
7
|
+
@site = site
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def request
|
|
11
|
+
controller.request
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def params
|
|
15
|
+
controller.params
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def session
|
|
19
|
+
controller.session
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def current_user
|
|
23
|
+
controller.send(:current_user) if controller.respond_to?(:current_user, true)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def owner
|
|
27
|
+
site.owner if site.respond_to?(:owner)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
require "date"
|
|
2
|
+
require_relative "content_source"
|
|
3
|
+
require_relative "content_source_context"
|
|
4
|
+
|
|
5
|
+
module Plum
|
|
6
|
+
class ContentSourceRegistry
|
|
7
|
+
RESERVED_HANDLES = %w[entry entries forms globals nav site].freeze
|
|
8
|
+
HANDLE_PATTERN = /\A[a-z][a-z0-9_]*\z/
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@sources = {}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def register(handle, source = nil, &block)
|
|
15
|
+
raise ArgumentError, "Provide a source or a block, not both" if source && block
|
|
16
|
+
raise ArgumentError, "Content source is required" unless source || block
|
|
17
|
+
|
|
18
|
+
normalized_handle = normalize_handle(handle)
|
|
19
|
+
validate_handle!(normalized_handle)
|
|
20
|
+
|
|
21
|
+
@sources[normalized_handle] = source || block
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def handles
|
|
25
|
+
@sources.keys
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def clear
|
|
29
|
+
@sources.clear
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def to_liquid_context(controller:, site:)
|
|
33
|
+
context = ContentSourceContext.new(controller: controller, site: site)
|
|
34
|
+
|
|
35
|
+
@sources.each_with_object({}) do |(handle, source), hash|
|
|
36
|
+
hash[handle] = resolve_source(handle, source, context)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def normalize_handle(handle)
|
|
43
|
+
handle.to_s
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def validate_handle!(handle)
|
|
47
|
+
raise ArgumentError, "Content source handle cannot be blank" if handle.blank?
|
|
48
|
+
unless handle.match?(HANDLE_PATTERN)
|
|
49
|
+
raise ArgumentError, "Content source handle must use lowercase letters, numbers, and underscores"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if RESERVED_HANDLES.include?(handle)
|
|
53
|
+
raise ArgumentError, "`#{handle}` is reserved by Plum's Liquid context"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def resolve_source(handle, source, context)
|
|
58
|
+
source = constantize_source(source)
|
|
59
|
+
value =
|
|
60
|
+
if source.respond_to?(:call)
|
|
61
|
+
source.call(context)
|
|
62
|
+
elsif source.respond_to?(:to_liquid)
|
|
63
|
+
source.to_liquid
|
|
64
|
+
elsif source.respond_to?(:new)
|
|
65
|
+
adapter = source.new(context)
|
|
66
|
+
unless adapter.respond_to?(:to_liquid)
|
|
67
|
+
raise ContentSourceError, "adapter #{source.name || source.inspect} must implement #to_liquid"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
adapter.to_liquid
|
|
71
|
+
else
|
|
72
|
+
source
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
normalize_for_liquid(value)
|
|
76
|
+
rescue ContentSourceError
|
|
77
|
+
raise
|
|
78
|
+
rescue StandardError => e
|
|
79
|
+
raise ContentSourceError, "Content source `#{handle}` failed: #{e.message}"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def constantize_source(source)
|
|
83
|
+
return source unless source.is_a?(String)
|
|
84
|
+
|
|
85
|
+
source.safe_constantize ||
|
|
86
|
+
raise(ContentSourceError, "Content source adapter `#{source}` could not be found")
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def normalize_for_liquid(value)
|
|
90
|
+
case value
|
|
91
|
+
when nil, String, Numeric, TrueClass, FalseClass, Date, Time
|
|
92
|
+
value
|
|
93
|
+
when Hash
|
|
94
|
+
value.each_with_object({}) do |(key, child), hash|
|
|
95
|
+
hash[key.to_s] = normalize_for_liquid(child)
|
|
96
|
+
end
|
|
97
|
+
when Array
|
|
98
|
+
value.map { |child| normalize_for_liquid(child) }
|
|
99
|
+
else
|
|
100
|
+
normalize_object_for_liquid(value)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def normalize_object_for_liquid(value)
|
|
105
|
+
if value.respond_to?(:to_liquid)
|
|
106
|
+
liquid_value = value.to_liquid
|
|
107
|
+
return liquid_value if liquid_value.equal?(value)
|
|
108
|
+
|
|
109
|
+
return normalize_for_liquid(liquid_value)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
if value.respond_to?(:to_a) && !value.is_a?(String)
|
|
113
|
+
return value.to_a.map { |child| normalize_for_liquid(child) }
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
raise ContentSourceError,
|
|
117
|
+
"#{value.class.name} is not Liquid-safe. Return a Hash, Array, scalar, or object with #to_liquid."
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
data/lib/plum/engine.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require_relative "configuration"
|
|
2
|
+
|
|
3
|
+
module Plum
|
|
4
|
+
class Engine < ::Rails::Engine
|
|
5
|
+
isolate_namespace Plum
|
|
6
|
+
config.paths["config/routes.rb"] = "config/plum_routes.rb"
|
|
7
|
+
config.paths["db/migrate"] = [ "db/engine_migrate" ]
|
|
8
|
+
|
|
9
|
+
initializer "plum.assets" do |app|
|
|
10
|
+
app.config.assets.paths << root.join("app/assets/javascripts")
|
|
11
|
+
app.config.assets.paths << root.join("app/javascript/controllers/plum")
|
|
12
|
+
app.config.assets.paths << root.join("vendor/javascript")
|
|
13
|
+
|
|
14
|
+
lexxy_spec = Gem.loaded_specs["lexxy"]
|
|
15
|
+
if lexxy_spec
|
|
16
|
+
lexxy_root = Pathname.new(lexxy_spec.gem_dir)
|
|
17
|
+
%w[app/assets/stylesheets app/javascript].each do |subpath|
|
|
18
|
+
path = lexxy_root.join(subpath)
|
|
19
|
+
app.config.assets.paths << path.to_s if path.exist?
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
initializer "plum.importmap", before: "importmap" do |app|
|
|
25
|
+
if app.config.respond_to?(:importmap)
|
|
26
|
+
app.config.importmap.paths << root.join("config/plum_importmap.rb")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Plum
|
|
2
|
+
module LiquidTags
|
|
3
|
+
class FormTag < Liquid::Tag
|
|
4
|
+
def initialize(tag_name, markup, options)
|
|
5
|
+
super
|
|
6
|
+
@handle_expression = Liquid::Expression.parse(markup.strip)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def render(context)
|
|
10
|
+
handle = context.evaluate(@handle_expression).to_s
|
|
11
|
+
renderer = context.registers[:form_renderer]
|
|
12
|
+
|
|
13
|
+
renderer ? renderer.call(handle) : ""
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/plum/version.rb
ADDED
data/lib/plum.rb
ADDED