View Source Beacon.Config (Beacon v0.2.1)

Configuration for sites.

Each site is started with this configuration and its values are stored in a registry that can be fetched at runtime or updated with update_value/3.

See new/1 for available options and examples.

Summary

Types

Register specific media types allowed for upload. Catchalls are not allowed.

A module that implements Beacon.RuntimeCSS.

Default meta tags added to new pages.

Host application Endpoint module.

Add extra fields to pages.

Add extra fields to pages.

Add extra fields to pages.

Attach steps into Beacon's internal life-cycle stages to inject custom functionality.

Life-cycle stages.

Path of a LiveView socket where Beacon should connect to.

Individual media type configs

Register providers and validations for media types. Catchalls are allowed.

Defines the mode which the site will operate.

Host application Repo module.

Host application Router module.

t()

Path to a custom Tailwind config.

Path to a custom Tailwind CSS

Register formats to handle templates, eg: [{:heex, "HEEx (HTML)"}].

Functions

From a Beacon.Config, fetch the asset config for a given media type, raising when unsuccessful.

Returns the Beacon.Config for site.

Searches a config option for the given media type.

Build a new %Beacon.Config{} instance to hold the entire configuration for each site.

Updates key with value for the site configuration, at runtime.

Types

Link to this type

allowed_media_accept_types()

View Source
@type allowed_media_accept_types() :: [media_type :: String.t()]

Register specific media types allowed for upload. Catchalls are not allowed.

@type css_compiler() :: module()

A module that implements Beacon.RuntimeCSS.

@type default_meta_tags() :: [%{required(binary()) => binary()}]

Default meta tags added to new pages.

@type endpoint() :: module()

Host application Endpoint module.

@type extra_asset_field() :: {media_type :: String.t(), [module()]}

Add extra fields to pages.

@type extra_asset_fields() :: [extra_asset_field()]

Add extra fields to pages.

@type extra_page_fields() :: [module()]

Add extra fields to pages.

@type lifecycle() :: [lifecycle_stage()]

Attach steps into Beacon's internal life-cycle stages to inject custom functionality.

@type lifecycle_stage() ::
  {:load_template,
   [
     {format :: String.t(),
      [
        {identifier :: atom(),
         fun :: (template :: String.t(), Beacon.Template.LoadMetadata.t() ->
                   {:cont, String.t()}
                   | {:halt, String.t()}
                   | {:halt, Exception.t()})}
      ]}
   ]}
  | {:render_template,
     [
       {format :: String.t(),
        [
          {identifier :: atom(),
           fun :: (Beacon.Template.t(), Beacon.Template.RenderMetadata.t() ->
                     {:cont, Beacon.Template.t()}
                     | {:halt, Beacon.Template.t()}
                     | {:halt, Exception.t()})}
        ]}
     ]}
  | {:after_create_page,
     [
       {identifier :: atom(),
        fun :: (Beacon.Content.Page.t() ->
                  {:cont, Beacon.Content.Page.t()} | {:halt, Exception.t()})}
     ]}
  | {:after_update_page,
     [
       {identifier :: atom(),
        fun :: (Beacon.Content.Page.t() ->
                  {:cont, Beacon.Content.Page.t()} | {:halt, Exception.t()})}
     ]}
  | {:after_publish_page,
     [
       {identifier :: atom(),
        fun :: (Beacon.Content.Page.t() ->
                  {:cont, Beacon.Content.Page.t()} | {:halt, Exception.t()})}
     ]}
  | {:upload_asset,
     [
       {identifier :: atom(),
        fun :: (Ecto.Schema.t(), Beacon.MediaLibrary.UploadMetadata.t() ->
                  {:cont, any()} | {:halt, Exception.t()})}
     ]}

Life-cycle stages.

@type live_socket_path() :: String.t()

Path of a LiveView socket where Beacon should connect to.

@type media_type_config() :: [
  processor:
    processor_fun :: (Beacon.MediaLibrary.UploadMetadata.t() ->
                        Beacon.MediaLibrary.UploadMetadata.t()),
  validations: [
    validation_fun ::
      (Ecto.Changeset.t(), Beacon.MediaLibrary.UploadMetadata.t() ->
         Ecto.Changeset.t())
      | {validation_fun :: (Ecto.Changeset.t(),
                            Beacon.MediaLibrary.UploadMetadata.t() ->
                              Ecto.Changeset.t()), validation_config :: term()}
  ],
  providers: [
    provider :: module() | {provider :: module(), provider_config :: term()}
  ]
]

Individual media type configs

@type media_type_configs() :: [{media_type :: String.t(), media_type_config()}]

Register providers and validations for media types. Catchalls are allowed.

@type mode() :: :live | :testing | :manual

Defines the mode which the site will operate.

Default is :live which will load resources during boot, broadcast events on content change, and execute operations asyncly. That's the normal mode for production.

The :testing mode is suited for testing environments, you should always use it when running tests that involve Beacon resources.

And the :manual mode is similar to :testing but it won't boot load any resource, it's useful to seed data.

You can always change to :live mode at runtime by calling Beacon.boot/1.

@type option() ::
  {:site, Beacon.Types.Site.t()}
  | {:endpoint, endpoint()}
  | {:router, router()}
  | {:repo, repo()}
  | {:mode, mode()}
  | {:css_compiler, css_compiler()}
  | {:tailwind_config, tailwind_config()}
  | {:tailwind_css, tailwind_css()}
  | {:live_socket_path, live_socket_path()}
  | {:safe_code_check, safe_code_check()}
  | {:template_formats, template_formats()}
  | {:assets, media_type_configs()}
  | {:allowed_media_accept_types, allowed_media_accept_types()}
  | {:lifecycle, lifecycle()}
  | {:extra_page_fields, extra_page_fields()}
  | {:extra_asset_fields, extra_asset_fields()}
  | {:default_meta_tags, default_meta_tags()}
@type repo() :: module()

Host application Repo module.

@type router() :: module()

Host application Router module.

@type safe_code_check() :: boolean()

Check safety of Elixir code using https://github.com/TheFirstAvenger/safe_code

@type t() :: %Beacon.Config{
  allowed_media_accept_types: allowed_media_accept_types(),
  assets: media_type_configs(),
  css_compiler: css_compiler(),
  default_meta_tags: default_meta_tags(),
  endpoint: endpoint(),
  extra_asset_fields: extra_asset_fields(),
  extra_page_fields: extra_page_fields(),
  lifecycle: lifecycle(),
  live_socket_path: live_socket_path(),
  mode: mode(),
  repo: repo(),
  router: router(),
  safe_code_check: safe_code_check(),
  site: Beacon.Types.Site.t(),
  tailwind_config: tailwind_config(),
  tailwind_css: tailwind_css(),
  template_formats: template_formats()
}
@type tailwind_config() :: Path.t()

Path to a custom Tailwind config.

Example

# use the config file `priv/tailwind.config.js` from your app named `my_app`
Path.join(Application.app_dir(:my_app, "priv"), "tailwind.config.js")

See Beacon.RuntimeCSS.TailwindCompiler for more info.

@type tailwind_css() :: Path.t()

Path to a custom Tailwind CSS

Note that Tailwind base, components, and utilities must be imported in this file.

Example

# use the file `assets/css/app.css` from your app named `my_app`
Path.join([Application.app_dir(:my_app, "assets"), "css", "app.css"])

See Beacon.RuntimeCSS.TailwindCompiler for more info.

@type template_formats() :: [{format :: atom(), description :: String.t()}]

Register formats to handle templates, eg: [{:heex, "HEEx (HTML)"}].

Beacon provides two formats built-in, HEEx and Markdown, but you can register your own as long as you also implement the life-cycle stages :load_template and :render_template.

The description is used on user interfaces as Beacon Admin.

Functions

Link to this function

config_for_media_type(beacon_config, media_type)

View Source
@spec config_for_media_type(t(), String.t()) :: media_type_config()

From a Beacon.Config, fetch the asset config for a given media type, raising when unsuccessful.

Example

iex> beacon_config = Beacon.Config.fetch!(:some_site)
iex> jpeg_config = config_for_media_type(beacon_config, "image/jpeg")
@spec fetch!(Beacon.Types.Site.t()) :: t()

Returns the Beacon.Config for site.

Link to this function

get_media_type_config(configs, media_type)

View Source
@spec get_media_type_config(media_type_configs(), String.t()) ::
  media_type_config() | nil
@spec get_media_type_config(extra_asset_fields(), String.t()) ::
  extra_asset_field() | nil

Searches a config option for the given media type.

For config options based on media type, such as :assets and :extra_asset_fields, this function will check for the presence of media_type, returning the config for that specific type, or nil if the type is not present.

Examples

iex> beacon_config = Beacon.Config.fetch!(:some_site)
iex> jpeg_config = config_for_media_type(beacon_config.assets, "image/jpeg")

iex> beacon_config = Beacon.Config.fetch!(:some_site)
iex> webp_config = config_for_media_type(beacon_config.extra_asset_fields, "image/webp")

iex> beacon_config = Beacon.Config.fetch!(:some_site)
iex> nil = config_for_media_type(beacon_config.assets, "invalid/foo")
@spec new([option()]) :: t()

Build a new %Beacon.Config{} instance to hold the entire configuration for each site.

Options

Note that the default config is merged with your config.

Note that the default config is merged with your config.

Example

iex> Beacon.Config.new(
  site: :my_site,
  endpoint: MyAppWeb.Endpoint,
  router: MyAppWeb.Router,
  repo: MyApp.Repo,
  tailwind_config: Path.join(Application.app_dir(:my_app, "priv"), "tailwind.config.js"),
  tailwind_css: Path.join([Application.app_dir(:my_app, "assets"), "css", "app.css"]),
  template_formats: [
    {:custom_format, "My Custom Format"}
  ],
  lifecycle: [
    load_template: [
      {:custom_format,
       [
         validate: fn template, _metadata -> MyEngine.validate(template) end
       ]}
    ],
    render_template: [
      {:custom_format,
       [
         assigns: fn %Phoenix.LiveView.Rendered{static: template} , %{assigns: assigns} -> MyEngine.parse_to_html(template, assigns) end
       ]}
    ],
    after_publish_page: [
      notify_admin: fn page -> {:cont, MyApp.Admin.send_email(page)} end
    ]
  ]
)
%Beacon.Config{
  site: :my_site,
  endpoint: MyAppWeb.Endpoint,
  router: MyAppWeb.Router,
  repo: MyApp.Repo,
  mode: :live,
  css_compiler: Beacon.RuntimeCSS.TailwindCompiler,
  tailwind_config: "/my_app/priv/tailwind.config.js",
  tailwind_css: "/my_app/assets/css/app.css",
  live_socket_path: "/live",
  safe_code_check: false,
  template_formats: [
    heex: "HEEx (HTML)",
    markdown: "Markdown (GitHub Flavored version)",
    custom_format: "My Custom Format"
  ],
  media_types: ["image/jpeg", "image/gif", "image/png", "image/webp"],
  assets:[
    {"image/*", [providers: [Beacon.MediaLibrary.Provider.Repo], validations: [&SomeModule.some_function/2]]},
  ],
  lifecycle: [
    load_template: [
      heex: [],
      markdown: [
        convert_to_html: &Beacon.Template.Markdown.convert_to_html/2,
      ],
      custom_format: [
        validate: #Function<41.3316493/2 in :erl_eval.expr/6>
      ]
    ],
    render_template: [
      heex: [],
      markdown: [],
      custom_format: [
        assigns: #Function<41.3316493/2 in :erl_eval.expr/6>
      ]
    ],
    after_create_page: [],
    after_update_page: [],
    after_publish_page: [
      notify_admin: #Function<42.3316493/1 in :erl_eval.expr/6>
    ],
    upload_asset: [],
  ],
  extra_page_fields: [],
  extra_asset_fields: [],
  default_meta_tags: []
}
Link to this function

update_value(site, key, value)

View Source
@spec update_value(Beacon.Types.Site.t(), atom(), any()) :: t() | :error

Updates key with value for the site configuration, at runtime.