Packages
phoenix_kit
1.4.9
1.7.211
1.7.210
1.7.209
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/phoenix_kit_web/live/modules/blogging/blog.html.heex
<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title={@page_title}
current_path={@current_path}
project_title={@project_title}
current_locale={@current_locale}
>
<div class="container mx-auto px-4 py-6 space-y-6">
<div class="space-y-4">
<div class="flex flex-col md:flex-row gap-3 md:items-center md:justify-between">
<div>
<p class="text-sm uppercase tracking-wide text-base-content/60">
{gettext("Blogging")}
</p>
<h1 class="text-3xl font-bold text-base-content">
{(@current_blog && @current_blog["name"]) || @blog_slug || gettext("Blog")}
</h1>
</div>
<div class="flex gap-2">
<button type="button" class="btn btn-primary btn-sm" phx-click="create_post">
<.icon name="hero-plus-circle" class="w-4 h-4 mr-1" /> {gettext("Create %{blog} Post",
blog: (@current_blog && @current_blog["name"]) || @blog_slug || gettext("Blog")
)}
</button>
</div>
</div>
<div class="flex-1">
<div class="flex flex-col md:flex-row gap-3 md:items-center md:justify-between mb-4">
<span class="text-sm text-base-content/70">
{gettext("Showing %{count} posts", count: length(@posts))}
</span>
<button type="button" class="btn btn-outline btn-sm shadow-none" phx-click="refresh">
<.icon name="hero-arrow-path" class="w-4 h-4 mr-1" /> {gettext("Refresh")}
</button>
</div>
<%= if @posts == [] do %>
<div class="card bg-base-100 shadow-sm border border-base-200">
<div class="card-body">
<h3 class="text-lg font-semibold text-base-content">{gettext("No posts yet")}</h3>
<p class="text-sm text-base-content/70">
{gettext("Create your first post to start sharing content.")}
</p>
</div>
</div>
<% else %>
<div class="grid gap-4">
<%= for post <- @posts do %>
<div class="card bg-base-100 shadow-sm border border-base-200">
<div class="card-body p-4 md:p-5 flex flex-col md:flex-row md:items-center md:justify-between gap-4">
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2 text-xs uppercase tracking-wide text-base-content/60">
<span>{format_datetime(post)}</span>
</div>
<h3 class="text-xl font-semibold text-base-content mt-1 truncate">
{post.metadata.title || gettext("Untitled post")}
</h3>
<p class="text-xs text-base-content/50 mt-1 font-mono truncate">
{post.path}
</p>
</div>
<div class="flex gap-2 flex-wrap">
<%!-- Show buttons for all languages (enabled and disabled) in consistent order --%>
<% all_languages =
(post.available_languages ++ @enabled_languages)
|> Enum.uniq()
|> Enum.sort() %>
<%= for lang_code <- all_languages do %>
<% lang_path =
Path.join([
Path.dirname(post.path),
"#{lang_code}.phk"
])
lang_info =
PhoenixKitWeb.Live.Modules.Blogging.get_language_info(lang_code)
flag = if lang_info, do: lang_info.flag, else: ""
file_exists = lang_code in post.available_languages
is_enabled = lang_code in @enabled_languages
# Read language-specific metadata for status
lang_metadata =
if file_exists do
case PhoenixKitWeb.Live.Modules.Blogging.read_post(
@blog_slug,
lang_path
) do
{:ok, lang_post} -> lang_post.metadata
_ -> nil
end
else
nil
end %>
<%= if file_exists do %>
<%!-- Language card with status, edit, and view buttons --%>
<div class="flex flex-col gap-1 justify-between">
<div class="flex gap-1 items-center">
<%!-- Status badge --%>
<%= if lang_metadata do %>
<button
type="button"
phx-click="toggle_status"
phx-value-path={lang_path}
phx-value-current-status={lang_metadata.status}
class={[
"badge badge-sm cursor-pointer hover:brightness-90 transition-all",
case lang_metadata.status do
"published" -> "badge-success"
"archived" -> "badge-neutral"
_ -> "badge-warning"
end
]}
title={gettext("Click to change status")}
>
{lang_metadata.status}
</button>
<%!-- View button for published posts --%>
<%= if lang_metadata.status == "published" do %>
<a
href={
PhoenixKitWeb.BlogHTML.build_post_url(
@blog_slug,
post,
lang_code
)
}
target="_blank"
class="badge badge-sm badge-ghost cursor-pointer hover:badge-primary"
title={gettext("View on public site")}
>
<.icon name="hero-arrow-top-right-on-square" class="w-3 h-3" />
</a>
<% end %>
<% end %>
</div>
<%!-- Edit button --%>
<.link
navigate={
PhoenixKit.Utils.Routes.path(
"/admin/blogging/#{post.blog}/edit?path=#{URI.encode(lang_path)}",
locale: @current_locale
)
}
class={[
"btn btn-sm shadow-none",
if(is_enabled,
do: "btn-outline",
else: "bg-base-200 text-base-content/60 border-base-300"
)
]}
title={
if lang_info,
do: "Edit #{lang_info.name}",
else: "Edit #{lang_code}"
}
>
<.icon name="hero-pencil-square" class="w-4 h-4 mr-1" />
<span class="text-lg">{flag}</span> {String.upcase(lang_code)}
</.link>
</div>
<% else %>
<%!-- Add button for missing files (only if language is enabled) --%>
<%= if is_enabled do %>
<div class="flex flex-col gap-1">
<%!-- Empty space for alignment --%>
<div class="h-5"></div>
<%!-- Add button --%>
<button
type="button"
phx-click="add_language"
phx-value-path={post.path}
phx-value-language={lang_code}
class="btn btn-success btn-sm bg-green-50 hover:bg-green-100 text-success shadow-none"
title={
if lang_info,
do: "Add #{lang_info.name}",
else: "Add #{lang_code}"
}
>
<.icon name="hero-plus-circle" class="w-4 h-4 mr-1" />
<span class="text-lg">{flag}</span> {String.upcase(lang_code)}
</button>
</div>
<% end %>
<% end %>
<% end %>
</div>
</div>
</div>
<% end %>
</div>
<% end %>
</div>
</div>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>