Packages
phoenix_kit
1.7.64
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/modules/posts/web/details.html.heex
<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title={@page_title}
current_path={@url_path}
project_title={@project_title}
>
<div class="container flex flex-col mx-auto px-4 py-6">
<%!-- Header Section --%>
<.admin_page_header back={Routes.path("/admin/posts")}>
<:actions>
<%= if can_edit_post?(@current_user, @post) do %>
<.link
href={Routes.path("/admin/posts/#{@post.uuid}/edit")}
class="btn btn-outline btn-sm"
>
<.icon name="hero-pencil" class="w-4 h-4" /> Edit
</.link>
<button
phx-click="change_status"
phx-value-status="draft"
class="btn btn-ghost btn-sm"
title="Move to Draft"
>
<.icon name="hero-pause" class="w-4 h-4" />
</button>
<button
phx-click="change_status"
phx-value-status="public"
class="btn btn-ghost btn-sm"
title="Publish"
>
<.icon name="hero-play" class="w-4 h-4" />
</button>
<button
phx-click="change_status"
phx-value-status="unlisted"
class="btn btn-ghost btn-sm"
title="Make Unlisted"
>
<.icon name="hero-eye-slash" class="w-4 h-4" />
</button>
<button
phx-click="delete_post"
data-confirm="Are you sure you want to delete this post?"
class="btn btn-ghost btn-sm text-error"
title="Delete Post"
>
<.icon name="hero-trash" class="w-4 h-4" />
</button>
<% end %>
</:actions>
</.admin_page_header>
<%!-- Main Content --%>
<div class="max-w-4xl mx-auto space-y-6">
<%!-- Post Card --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<%!-- Post Header --%>
<div class="flex items-start justify-between mb-4">
<div class="flex-1">
<%!-- Post Type Badge --%>
<div class="mb-2">
<span class={format_type_badge_class(@post.type)}>
{format_post_type(@post.type)}
</span>
<span class={format_status_badge_class(@post.status)}>
{format_status(@post.status)}
</span>
</div>
<%!-- Title --%>
<h1 class="text-2xl sm:text-4xl font-bold text-base-content mb-2">
{@post.title}
</h1>
<%!-- Subtitle --%>
<%= if @post.sub_title do %>
<p class="text-xl text-base-content/70 mb-4">
{@post.sub_title}
</p>
<% end %>
<%!-- Author & Date --%>
<div class="flex items-center gap-4 text-sm text-base-content/60">
<div class="flex items-center gap-2">
<.icon name="hero-user-circle" class="w-5 h-5" />
<span>
<%= if @post.user do %>
{@post.user.email}
<% else %>
Unknown
<% end %>
</span>
</div>
<div class="flex items-center gap-2">
<.icon name="hero-clock" class="w-5 h-5" />
<span>
{Calendar.strftime(@post.inserted_at, "%B %d, %Y at %I:%M %p")}
</span>
</div>
</div>
</div>
</div>
<%!-- Stats --%>
<div class="flex gap-6 my-4 text-sm">
<%= if @show_view_count do %>
<div class="flex items-center gap-2">
<.icon name="hero-eye" class="w-5 h-5 text-base-content/60" />
<span class="font-semibold">{@post.view_count}</span>
<span class="text-base-content/60">views</span>
</div>
<% end %>
<%= if @likes_enabled do %>
<div class="flex items-center gap-2">
<.icon name="hero-heart" class="w-5 h-5 text-base-content/60" />
<span class="font-semibold">{@post.like_count}</span>
<span class="text-base-content/60">likes</span>
</div>
<% end %>
<%= if @comments_enabled do %>
<div class="flex items-center gap-2">
<.icon name="hero-chat-bubble-left" class="w-5 h-5 text-base-content/60" />
<span class="font-semibold">{@post.comment_count}</span>
<span class="text-base-content/60">comments</span>
</div>
<% end %>
</div>
<div class="divider"></div>
<%!-- Featured Image (if any) --%>
<% featured_image = Enum.find(@post.media || [], fn m -> m.position == 1 end) %>
<%= if featured_image do %>
<div class="mb-6">
<img
src={
PhoenixKit.Modules.Storage.URLSigner.signed_url(
featured_image.file_uuid,
"original"
)
}
alt={featured_image.file && featured_image.file.original_file_name}
class="w-full rounded-lg object-cover max-h-96"
/>
</div>
<% end %>
<%!-- Content (Markdown Rendered) --%>
<.markdown_content content={@rendered_content} />
<%!-- Media Gallery (if any) --%>
<% gallery_media = Enum.filter(@post.media || [], fn m -> m.position != 1 end) %>
<%= if length(gallery_media) > 0 do %>
<div class="divider"></div>
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
<%= for media <- gallery_media do %>
<div class="aspect-square rounded-lg overflow-hidden">
<img
src={
PhoenixKit.Modules.Storage.URLSigner.signed_url(media.file_uuid, "original")
}
alt={media.file && media.file.original_file_name}
class="w-full h-full object-cover"
/>
</div>
<% end %>
</div>
<% end %>
<%!-- Tags --%>
<%= if @post.tags && length(@post.tags) > 0 do %>
<div class="divider"></div>
<div class="flex flex-wrap gap-2">
<%= for tag <- @post.tags do %>
<div class="badge badge-outline badge-lg h-auto">
#{tag.name}
</div>
<% end %>
</div>
<% end %>
<%!-- Groups --%>
<%= if @post.groups && length(@post.groups) > 0 do %>
<div class="divider"></div>
<div class="space-y-2">
<h3 class="font-semibold text-base-content/70">Collections:</h3>
<div class="flex flex-wrap gap-2">
<%= for group <- @post.groups do %>
<div class="badge badge-secondary badge-lg h-auto">
<.icon name="hero-folder" class="w-4 h-4 mr-1" />
{group.name}
</div>
<% end %>
</div>
</div>
<% end %>
<%!-- Like Button --%>
<%= if @likes_enabled do %>
<div class="divider"></div>
<div class="flex justify-center">
<button
phx-click="like_post"
class={[
"btn gap-2",
if(@liked_by_user, do: "btn-error", else: "btn-outline")
]}
>
<.icon
name={if @liked_by_user, do: "hero-heart-solid", else: "hero-heart"}
class="w-5 h-5"
/>
{if @liked_by_user, do: "Unlike", else: "Like"}
</button>
</div>
<% end %>
</div>
</div>
<%!-- Comments Section (via standalone CommentsComponent) --%>
<%= if @comments_enabled do %>
<.live_component
module={PhoenixKit.Modules.Comments.Web.CommentsComponent}
id={"post-comments-#{@post.uuid}"}
resource_type="post"
resource_id={@post.uuid}
current_user={@current_user}
/>
<% end %>
</div>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>