168 lines
4.1 KiB
Elixir
168 lines
4.1 KiB
Elixir
defmodule Blogex.Components do
|
|
@moduledoc """
|
|
Phoenix function components for rendering blog content.
|
|
|
|
These are unstyled building blocks — the host app wraps them
|
|
in its own layout and applies its own CSS.
|
|
|
|
## Usage in a LiveView or template:
|
|
|
|
import Blogex.Components
|
|
|
|
<.post_index blog={@blog_module} posts={@posts} />
|
|
<.post_show post={@post} />
|
|
<.tag_list tags={@tags} base_path={@base_path} />
|
|
"""
|
|
|
|
use Phoenix.Component
|
|
|
|
@doc """
|
|
Renders a list of post previews.
|
|
|
|
## Attributes
|
|
|
|
* `:posts` - list of `%Blogex.Post{}` structs (required)
|
|
* `:base_path` - base URL path for post links (required)
|
|
"""
|
|
attr :posts, :list, required: true
|
|
attr :base_path, :string, required: true
|
|
|
|
def post_index(assigns) do
|
|
~H"""
|
|
<div class="blogex-post-index">
|
|
<article :for={post <- @posts} class="blogex-post-preview">
|
|
<header>
|
|
<h2>
|
|
<a href={"#{@base_path}/#{post.id}"}>{post.title}</a>
|
|
</h2>
|
|
<.post_meta post={post} base_path={@base_path} />
|
|
</header>
|
|
<p class="blogex-post-description">{post.description}</p>
|
|
</article>
|
|
</div>
|
|
"""
|
|
end
|
|
|
|
@doc """
|
|
Renders a full blog post.
|
|
|
|
## Attributes
|
|
|
|
* `:post` - a `%Blogex.Post{}` struct (required)
|
|
* `:base_path` - base URL path for tag links (required)
|
|
"""
|
|
attr :post, :map, required: true
|
|
attr :base_path, :string, required: true
|
|
|
|
def post_show(assigns) do
|
|
~H"""
|
|
<article class="blogex-post">
|
|
<header class="blogex-post-header">
|
|
<h1>{@post.title}</h1>
|
|
<.post_meta post={@post} base_path={@base_path} />
|
|
</header>
|
|
<div class="blogex-post-body">
|
|
{Phoenix.HTML.raw(@post.body)}
|
|
</div>
|
|
</article>
|
|
"""
|
|
end
|
|
|
|
@doc """
|
|
Renders post metadata (date, author, tags).
|
|
|
|
## Attributes
|
|
|
|
* `:post` - a `%Blogex.Post{}` struct (required)
|
|
* `:base_path` - base URL path for tag links (required)
|
|
* `:current_tag` - currently selected tag for highlighting (optional)
|
|
"""
|
|
attr :post, :map, required: true
|
|
attr :base_path, :string, required: true
|
|
attr :current_tag, :string, default: nil
|
|
|
|
def post_meta(assigns) do
|
|
~H"""
|
|
<div class="blogex-post-meta">
|
|
<time datetime={Date.to_iso8601(@post.date)}>
|
|
{Calendar.strftime(@post.date, "%B %d, %Y")}
|
|
</time>
|
|
<span :if={@post.author} class="blogex-post-author">
|
|
by {@post.author}
|
|
</span>
|
|
<a
|
|
:for={tag <- @post.tags}
|
|
href={"#{@base_path}/tag/#{tag}"}
|
|
class={["blogex-tag-link", tag == @current_tag && "blogex-tag-active"]}
|
|
>
|
|
{tag}
|
|
</a>
|
|
</div>
|
|
"""
|
|
end
|
|
|
|
@doc """
|
|
Renders a tag cloud / tag list with links.
|
|
|
|
## Attributes
|
|
|
|
* `:tags` - list of tag strings (required)
|
|
* `:base_path` - base URL path (required)
|
|
* `:current_tag` - currently selected tag for highlighting (optional)
|
|
"""
|
|
attr :tags, :list, required: true
|
|
attr :base_path, :string, required: true
|
|
attr :current_tag, :string, default: nil
|
|
|
|
def tag_list(assigns) do
|
|
~H"""
|
|
<nav class="blogex-tag-list">
|
|
<a
|
|
:for={tag <- @tags}
|
|
href={"#{@base_path}/tag/#{tag}"}
|
|
class={["blogex-tag-link", tag == @current_tag && "blogex-tag-active"]}
|
|
>
|
|
{tag}
|
|
</a>
|
|
</nav>
|
|
"""
|
|
end
|
|
|
|
@doc """
|
|
Renders pagination controls.
|
|
|
|
## Attributes
|
|
|
|
* `:page` - current page number (required)
|
|
* `:total_pages` - total number of pages (required)
|
|
* `:base_path` - base URL path (required)
|
|
"""
|
|
attr :page, :integer, required: true
|
|
attr :total_pages, :integer, required: true
|
|
attr :base_path, :string, required: true
|
|
|
|
def pagination(assigns) do
|
|
~H"""
|
|
<nav :if={@total_pages > 1} class="blogex-pagination">
|
|
<a
|
|
:if={@page > 1}
|
|
href={"#{@base_path}?page=#{@page - 1}"}
|
|
class="blogex-pagination-prev"
|
|
>
|
|
← Newer
|
|
</a>
|
|
<span class="blogex-pagination-info">
|
|
Page {@page} of {@total_pages}
|
|
</span>
|
|
<a
|
|
:if={@page < @total_pages}
|
|
href={"#{@base_path}?page=#{@page + 1}"}
|
|
class="blogex-pagination-next"
|
|
>
|
|
Older →
|
|
</a>
|
|
</nav>
|
|
"""
|
|
end
|
|
end
|