Sayfa.Block (Sayfa v0.5.0)

Copy Markdown View Source

Registry and lookup functions for blocks.

Maps block names to block modules. By default, fifteen built-in blocks are registered. Custom blocks can be added via application config:

config :sayfa, :blocks, [MyApp.Blocks.Banner | Sayfa.Block.default_blocks()]

Block Helper

The build_helper/1 function creates a closure that templates use as @block:

block_fn = Sayfa.Block.build_helper(site: config, content: content, contents: all_contents, lang: :en)
block_fn.(:recent_content, limit: 5)
#=> "<section>..."

Examples

iex> length(Sayfa.Block.default_blocks())
14

iex> Sayfa.Block.find_by_name(:header)
Sayfa.Blocks.Header

iex> Sayfa.Block.find_by_name(:nonexistent)
nil

Summary

Functions

Returns all registered block modules.

Builds the @block helper function for templates.

Returns the list of built-in block modules.

Escapes HTML special characters in a string.

Finds a block module by its atom name.

Returns an SVG icon for the given social platform label.

Returns the rel attribute for a social link.

Functions

all()

@spec all() :: [module()]

Returns all registered block modules.

Reads from application config, falling back to default_blocks/0.

Examples

iex> blocks = Sayfa.Block.all()
iex> is_list(blocks)
true

build_helper(context)

@spec build_helper(keyword()) :: (atom(), keyword() -> String.t())

Builds the @block helper function for templates.

Takes a keyword list of context and returns a function that looks up a block by name, merges the context with caller options, and calls render/1.

Context Keys

  • :site — resolved config map
  • :content — current Sayfa.Content struct (may be nil)
  • :contents — list of all site contents
  • :lang — current language atom
  • :t — translation function (String.t() -> String.t())

Examples

block_fn = Sayfa.Block.build_helper(site: config, content: content, contents: [], lang: :en)
block_fn.(:recent_content, limit: 5)
#=> "<section>..."

block_fn.(:nonexistent, [])
#=> ""

default_blocks()

@spec default_blocks() :: [module()]

Returns the list of built-in block modules.

Examples

iex> length(Sayfa.Block.default_blocks())
14

escape_html(text)

@spec escape_html(String.t()) :: String.t()

Escapes HTML special characters in a string.

Examples

iex> Sayfa.Block.escape_html("<script>alert('xss')</script>")
"&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;"

iex> Sayfa.Block.escape_html("Hello & World")
"Hello &amp; World"

find_by_name(name)

@spec find_by_name(atom()) :: module() | nil

Finds a block module by its atom name.

Examples

iex> Sayfa.Block.find_by_name(:header)
Sayfa.Blocks.Header

iex> Sayfa.Block.find_by_name(:nonexistent)
nil

social_icon(label, size \\ "w-5 h-5")

@spec social_icon(String.t(), String.t()) :: String.t()

Returns an SVG icon for the given social platform label.

Supports 24 platforms with filled brand icons (fill="currentColor"): GitHub, X/Twitter, Mastodon, Goodreads, LinkedIn, YouTube, Instagram, Bluesky, Threads, Discord, Reddit, Stack Overflow, Facebook, Medium, Dev.to, Telegram, Ko-fi, Codeberg, Letterboxd, Spotify, Hacker News, and Twitch.

Utility icons (Email, RSS/Feed) use outlined style. Unknown platforms get a generic link icon fallback.

Labels are case-insensitive and support aliases (e.g., "yt" for YouTube, "bsky" for Bluesky, "so" for Stack Overflow).

Examples

iex> Sayfa.Block.social_icon("github", "w-4 h-4") |> String.contains?("svg")
true

iex> Sayfa.Block.social_icon("unknown", "w-5 h-5") |> String.contains?("svg")
true

social_rel(label)

@spec social_rel(String.t()) :: String.t()

Returns the rel attribute for a social link.

Returns "me noopener" for Mastodon links and "noopener" for all others.

Examples

iex> Sayfa.Block.social_rel("Mastodon")
"me noopener"

iex> Sayfa.Block.social_rel("GitHub")
"noopener"