Packages

phoenix_kit

1.7.21
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
phoenix_kit lib modules publishing web index.html.heex
Raw

lib/modules/publishing/web/index.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 flex-col mx-auto px-4 py-6">
<%!-- Header Section --%>
<header class="w-full relative mb-6">
<%!-- Back Button (Left aligned) --%>
<.link
navigate={Routes.path("/admin", locale: @current_locale)}
class="btn btn-outline btn-primary btn-sm absolute left-0 top-0 -mb-12"
>
<.icon name="hero-arrow-left" class="w-4 h-4 mr-2" /> Back to Dashboard
</.link>
<%!-- Title Section --%>
<div class="text-center">
<h1 class="text-4xl font-bold text-base-content mb-3">{gettext("Publishing")}</h1>
<p class="text-lg text-base-content">
{gettext(
"Monitor publishing activity, jump into blog workspaces, and guide your team toward new content opportunities."
)}
</p>
</div>
</header>
<div class="space-y-8">
<%= if @empty_state? do %>
<div class="card bg-base-100 border border-dashed border-base-300 shadow-sm">
<div class="card-body items-center text-center space-y-4">
<div class="rounded-full bg-base-200 p-3 text-primary">
<.icon name="hero-document-text" class="w-8 h-8" />
</div>
<h2 class="text-2xl font-semibold text-base-content">
{gettext("No publishing groups yet")}
</h2>
<p class="text-base text-base-content/70 max-w-xl">
{gettext(
"Publishing lets you organize content into themed workspaces with their own publishing flows. Set up your first publishing group to start drafting posts."
)}
</p>
<div class="flex flex-wrap justify-center gap-3">
<.link
href={Routes.path("/admin/settings/publishing/new", locale: @current_locale)}
class="btn btn-primary btn-sm"
>
<.icon name="hero-plus" class="w-4 h-4 mr-1" /> {gettext(
"Create Publishing Group"
)}
</.link>
<.link
navigate={Routes.path("/admin/settings/publishing", locale: @current_locale)}
class="btn btn-outline btn-sm"
>
<.icon name="hero-information-circle" class="w-4 h-4 mr-1" /> {gettext(
"Learn More"
)}
</.link>
</div>
</div>
</div>
<% else %>
<div class="grid gap-4 md:grid-cols-2 xl:grid-cols-5">
<div class="stat bg-base-100 shadow-sm rounded-lg border border-base-200">
<div class="stat-title text-sm text-base-content/70">
{gettext("Publishing Groups")}
</div>
<div class="stat-value text-3xl text-base-content">
{@dashboard_summary.total_blogs}
</div>
</div>
<div class="stat bg-base-100 shadow-sm rounded-lg border border-base-200">
<div class="stat-title text-sm text-base-content/70">{gettext("Total Posts")}</div>
<div class="stat-value text-3xl text-base-content">
{@dashboard_summary.total_posts}
</div>
</div>
<div class="stat bg-base-100 shadow-sm rounded-lg border border-base-200">
<div class="stat-title text-sm text-base-content/70">{gettext("Published")}</div>
<div class="stat-value text-3xl text-base-content">
{@dashboard_summary.published_posts}
</div>
</div>
<div class="stat bg-base-100 shadow-sm rounded-lg border border-base-200">
<div class="stat-title text-sm text-base-content/70">{gettext("Drafts")}</div>
<div class="stat-value text-3xl text-base-content">
{@dashboard_summary.draft_posts}
</div>
</div>
<div class="stat bg-base-100 shadow-sm rounded-lg border border-base-200">
<div class="stat-title text-sm text-base-content/70">{gettext("Archived Posts")}</div>
<div class="stat-value text-3xl text-base-content">
{@dashboard_summary.archived_posts}
</div>
</div>
</div>
<div class="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
<%= for insight <- @dashboard_insights do %>
<div class="card bg-base-100 shadow-sm border border-base-200 hover:border-primary/60 transition h-full">
<div class="card-body space-y-4 h-full flex flex-col">
<div class="flex items-start justify-between gap-3">
<div class="space-y-2">
<h3 class="text-xl font-semibold text-base-content">
<.link
navigate={
Routes.path("/admin/publishing/#{insight.slug}",
locale: @current_locale
)
}
class="hover:text-primary transition-colors"
>
{insight.name}
</.link>
</h3>
<p class="text-xs text-base-content/60">
{gettext("Slug")}: <code class="font-mono">{insight.slug}</code>
</p>
<p class="text-xs text-base-content/60">
<span class="whitespace-nowrap">{gettext("Last published")}: </span>
<%= if insight.last_published_at_text do %>
<span class="whitespace-nowrap">{insight.last_published_at_text}</span>
<% else %>
{gettext("No published posts yet")}
<% end %>
</p>
</div>
<span class="badge badge-ghost badge-lg text-xs px-4 py-3 whitespace-nowrap">
<%= if insight.mode == "slug" do %>
{gettext("Slug-based")}
<% else %>
{gettext("Timestamp-based")}
<% end %>
</span>
</div>
<div class="grid grid-cols-3 gap-3">
<div class="rounded-lg bg-base-200/60 px-3 py-2 text-center">
<p class="text-xs uppercase tracking-wide text-base-content/60 min-h-[1.25rem] flex items-center justify-center">
{gettext("Posts")}
</p>
<p class="font-semibold text-base-content">{insight.posts_count}</p>
</div>
<div class="rounded-lg bg-success/10 px-3 py-2 text-center">
<p class="text-xs uppercase tracking-wide text-success min-h-[1.25rem] flex items-center justify-center">
{gettext("Published")}
</p>
<p class="font-semibold text-success">{insight.published_count}</p>
</div>
<div class="rounded-lg bg-warning/10 px-3 py-2 text-center">
<p class="text-xs uppercase tracking-wide text-warning min-h-[1.25rem] flex items-center justify-center">
{gettext("Drafts")}
</p>
<p class="font-semibold text-warning">{insight.draft_count}</p>
</div>
</div>
<div class="min-h-[2rem]">
<%= if insight.languages != [] do %>
<div class="flex flex-wrap gap-2">
<span class="text-xs font-medium uppercase text-base-content/60">
{gettext("Languages")}:
</span>
<%= for language <- insight.languages do %>
<span class="badge badge-ghost badge-sm px-2 py-1">
{language
|> PhoenixKit.Modules.Languages.DialectMapper.extract_base()
|> String.upcase()}
</span>
<% end %>
</div>
<% else %>
<p class="text-xs text-base-content/60">
{gettext("Languages")}:
<span class="badge badge-ghost badge-sm px-2 py-1 uppercase">
{gettext("N/A")}
</span>
</p>
<% end %>
</div>
<div class="flex gap-2 mt-auto">
<.link
navigate={
Routes.path("/admin/publishing/#{insight.slug}", locale: @current_locale)
}
class="btn btn-outline btn-sm"
>
<.icon name="hero-arrow-right" class="w-4 h-4 mr-1" />
{gettext("Open")}
</.link>
<.link
navigate={
Routes.path(
"/admin/settings/publishing/#{insight.slug}/edit",
locale: @current_locale
)
}
class="btn btn-outline btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" />
{gettext("Settings")}
</.link>
<% blog_slug = insight.slug %>
<% url_prefix =
PhoenixKit.Config.get_url_prefix()
|> case do
"/" -> ""
prefix -> prefix
end %>
<%!-- Use first enabled language (default) for public URL, not UI locale --%>
<% default_language = List.first(@enabled_languages) %>
<% public_url =
if length(@enabled_languages) == 1 do
@endpoint_url <> url_prefix <> "/" <> blog_slug
else
@endpoint_url <> url_prefix <> "/#{default_language}/" <> blog_slug
end %>
<a
href={public_url}
target="_blank"
rel="noopener"
class="btn btn-outline btn-sm"
aria-label={gettext("View public site")}
>
<.icon name="hero-eye" class="w-4 h-4 mr-1" />
{gettext("View")}
</a>
</div>
</div>
</div>
<% end %>
</div>
<% end %>
</div>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>