add SettingsField struct and repeater field type for block settings
All checks were successful
deploy / deploy (push) Successful in 1m23s

Introduces typed settings schema with SettingsField struct, replaces
the read-only JSON textarea with a full repeater UI for info_card items.
Supports add, remove, reorder and inline editing of repeater items.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-02-27 00:54:13 +00:00
parent 3f97742c0b
commit 6fbd654d57
5 changed files with 470 additions and 52 deletions

View File

@@ -7,6 +7,7 @@ defmodule Berrypod.Pages.BlockTypes do
is present on a page.
"""
alias Berrypod.Pages.SettingsField
alias Berrypod.Products
alias Berrypod.Theme.PreviewData
@@ -18,13 +19,23 @@ defmodule Berrypod.Pages.BlockTypes do
icon: "hero-megaphone",
allowed_on: :all,
settings_schema: [
%{key: "title", label: "Title", type: :text, default: ""},
%{key: "description", label: "Description", type: :textarea, default: ""},
%{key: "cta_text", label: "Button text", type: :text, default: ""},
%{key: "cta_href", label: "Button link", type: :text, default: ""},
%{key: "secondary_cta_text", label: "Secondary button text", type: :text, default: ""},
%{key: "secondary_cta_href", label: "Secondary button link", type: :text, default: ""},
%{
%SettingsField{key: "title", label: "Title", type: :text, default: ""},
%SettingsField{key: "description", label: "Description", type: :textarea, default: ""},
%SettingsField{key: "cta_text", label: "Button text", type: :text, default: ""},
%SettingsField{key: "cta_href", label: "Button link", type: :text, default: ""},
%SettingsField{
key: "secondary_cta_text",
label: "Secondary button text",
type: :text,
default: ""
},
%SettingsField{
key: "secondary_cta_href",
label: "Secondary button link",
type: :text,
default: ""
},
%SettingsField{
key: "variant",
label: "Style",
type: :select,
@@ -38,23 +49,33 @@ defmodule Berrypod.Pages.BlockTypes do
icon: "hero-star",
allowed_on: :all,
settings_schema: [
%{key: "title", label: "Title", type: :text, default: "Featured products"},
%{key: "product_count", label: "Number of products", type: :number, default: 8},
%{
%SettingsField{
key: "title",
label: "Title",
type: :text,
default: "Featured products"
},
%SettingsField{
key: "product_count",
label: "Number of products",
type: :number,
default: 8
},
%SettingsField{
key: "layout",
label: "Layout",
type: :select,
options: ~w(section grid),
default: "section"
},
%{
%SettingsField{
key: "card_variant",
label: "Card style",
type: :select,
options: ~w(featured default minimal compact),
default: "featured"
},
%{
%SettingsField{
key: "columns",
label: "Columns",
type: :select,
@@ -69,11 +90,11 @@ defmodule Berrypod.Pages.BlockTypes do
icon: "hero-photo",
allowed_on: :all,
settings_schema: [
%{key: "title", label: "Title", type: :text, default: ""},
%{key: "description", label: "Description", type: :textarea, default: ""},
%{key: "image_url", label: "Image URL", type: :text, default: ""},
%{key: "link_text", label: "Link text", type: :text, default: ""},
%{key: "link_href", label: "Link URL", type: :text, default: ""}
%SettingsField{key: "title", label: "Title", type: :text, default: ""},
%SettingsField{key: "description", label: "Description", type: :textarea, default: ""},
%SettingsField{key: "image_url", label: "Image URL", type: :text, default: ""},
%SettingsField{key: "link_text", label: "Link text", type: :text, default: ""},
%SettingsField{key: "link_href", label: "Link URL", type: :text, default: ""}
]
},
"category_nav" => %{
@@ -99,8 +120,17 @@ defmodule Berrypod.Pages.BlockTypes do
icon: "hero-information-circle",
allowed_on: :all,
settings_schema: [
%{key: "title", label: "Title", type: :text, default: ""},
%{key: "items", label: "Items", type: :json, default: []}
%SettingsField{key: "title", label: "Title", type: :text, default: ""},
%SettingsField{
key: "items",
label: "Items",
type: :repeater,
default: [],
item_schema: [
%SettingsField{key: "label", label: "Label", type: :text, default: ""},
%SettingsField{key: "value", label: "Value", type: :text, default: ""}
]
}
]
},
"trust_badges" => %{
@@ -188,7 +218,7 @@ defmodule Berrypod.Pages.BlockTypes do
icon: "hero-envelope",
allowed_on: ["contact"],
settings_schema: [
%{key: "email", label: "Email", type: :text, default: "hello@example.com"}
%SettingsField{key: "email", label: "Email", type: :text, default: "hello@example.com"}
]
},
"order_tracking_card" => %{
@@ -205,8 +235,8 @@ defmodule Berrypod.Pages.BlockTypes do
icon: "hero-document-text",
allowed_on: ["about", "delivery", "privacy", "terms"],
settings_schema: [
%{key: "image_src", label: "Image", type: :text, default: ""},
%{key: "image_alt", label: "Image alt text", type: :text, default: ""}
%SettingsField{key: "image_src", label: "Image", type: :text, default: ""},
%SettingsField{key: "image_alt", label: "Image alt text", type: :text, default: ""}
]
},

View File

@@ -0,0 +1,16 @@
defmodule Berrypod.Pages.SettingsField do
@moduledoc "Defines a single field in a block's settings schema."
@type field_type :: :text | :textarea | :number | :select | :repeater
@type t :: %__MODULE__{
key: String.t(),
label: String.t(),
type: field_type(),
default: term(),
options: [String.t()] | nil,
item_schema: [t()] | nil
}
@enforce_keys [:key, :label, :type]
defstruct [:key, :label, :type, default: nil, options: nil, item_schema: nil]
end