Packages
phoenix_kit
1.7.19
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/modules/blogging/web/new.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 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/settings/blogging", 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 Blogging Settings
</.link>
<%!-- Title Section --%>
<div class="text-center">
<h1 class="text-4xl font-bold text-base-content mb-3">{gettext("Create a New Blog")}</h1>
<p class="text-lg text-base-content">
{gettext(
"Spin up a dedicated workspace for your content team. Choose the storage approach that fits the publishing experience you want to provide."
)}
</p>
</div>
</header>
<div class="max-w-2xl mx-auto space-y-6">
<div class="card bg-base-100 shadow-xl border border-base-200">
<div class="card-body space-y-6">
<.form
for={@form}
id="blog-create-form"
class="space-y-6"
phx-change="update_new_blog"
phx-submit="add_blog"
>
<div class="space-y-2">
<.input
field={@form[:name]}
type="text"
label={gettext("Blog Name")}
placeholder={gettext("e.g. Product Updates")}
required
/>
<p class="text-xs text-base-content/60">
{gettext("Used for display in the navigation and admin sections.")}
</p>
</div>
<div class="space-y-2">
<.input
field={@form[:slug]}
type="text"
label={gettext("Blog Slug")}
placeholder={gettext("e.g. product-updates")}
required
phx-change="manual_slug"
phx-debounce="150"
/>
<div class="space-y-1">
<p class="text-xs text-base-content/60">
{gettext("Used for the URL and the directory where blog files are stored.")}
</p>
<p class="text-xs font-medium text-base-content/70">
<span class="font-semibold">{gettext("Format")}:</span>
{gettext(
"Only lowercase letters (a-z), numbers (0-9), and hyphens (-) are allowed. Must not start or end with a hyphen."
)}
</p>
<p class="text-xs text-success">
✓ {gettext("Valid examples")}: <code class="font-mono">blog</code>, <code class="font-mono">
product-updates
</code>,
<code class="font-mono">news-2025</code>
</p>
<p class="text-xs text-error">
✗ {gettext("Invalid examples")}: <code class="font-mono">Blog</code>, <code class="font-mono">
product_updates
</code>, <code class="font-mono">-news</code>,
<code class="font-mono">
my blog
</code>
</p>
</div>
<% slug_value = @form[:slug].value || "" %>
<% slug_sample = if slug_value == "", do: gettext("your-blog"), else: slug_value %>
<% url_prefix =
PhoenixKit.Config.get_url_prefix()
|> case do
"/" -> ""
prefix -> prefix
end %>
<%!-- Use first enabled language (default) for preview URLs --%>
<% default_language = List.first(@enabled_languages) %>
<% timestamp_file_pattern =
"priv/blogging/#{slug_sample}/<YYYY-MM-DD>/<HH:mm>/<locale>.phk" %>
<% timestamp_url_pattern =
if length(@enabled_languages) == 1 do
@endpoint_url <> "#{url_prefix}/#{slug_sample}/<YYYY-MM-DD>/<HH:mm>"
else
@endpoint_url <>
"#{url_prefix}/#{default_language}/#{slug_sample}/<YYYY-MM-DD>/<HH:mm>"
end %>
<% slug_file_pattern = "priv/blogging/#{slug_sample}/<slug>/<locale>.phk" %>
<% slug_url_pattern =
if length(@enabled_languages) == 1 do
@endpoint_url <> "#{url_prefix}/#{slug_sample}/:post_slug"
else
@endpoint_url <> "#{url_prefix}/#{default_language}/#{slug_sample}/:post_slug"
end %>
</div>
<div class="form-control">
<label class="label">
<span class="label-text text-sm font-semibold text-base-content">
{gettext("Storage Mode")}
</span>
</label>
<div class="space-y-3">
<label class="cursor-pointer flex items-start gap-3 rounded-lg border border-base-300/70 bg-base-200/40 px-4 py-3 hover:border-primary/60 transition">
<input
type="radio"
name={@form[:mode].name}
value="timestamp"
class="radio radio-primary mt-1"
checked={@form[:mode].value == "timestamp"}
/>
<div>
<p class="font-medium text-base-content">{gettext("Timestamp-based")}</p>
<p class="text-sm text-base-content/70">
{gettext(
"Organizes posts in date/time folders. Great for news, updates, and chronological feeds."
)}
</p>
<div class="mt-2 space-y-1 text-xs text-base-content/70">
<p>
<span class="font-medium text-base-content">{gettext("Files")}: </span>
<code class="font-mono break-all">{timestamp_file_pattern}</code>
</p>
<p>
<span class="font-medium text-base-content">
{gettext("Public URL")}:
</span>
<code class="font-mono break-all">{timestamp_url_pattern}</code>
</p>
</div>
</div>
</label>
<label class="cursor-pointer flex items-start gap-3 rounded-lg border border-base-300/70 bg-base-200/40 px-4 py-3 hover:border-primary/60 transition">
<input
type="radio"
name={@form[:mode].name}
value="slug"
class="radio radio-primary mt-1"
checked={@form[:mode].value == "slug"}
/>
<div>
<p class="font-medium text-base-content">{gettext("Slug-based")}</p>
<p class="text-sm text-base-content/70">
{gettext(
"Uses semantic URLs and editable slugs. Ideal for documentation, guides, and evergreen content."
)}
</p>
<div class="mt-2 space-y-1 text-xs text-base-content/70">
<p>
<span class="font-medium text-base-content">{gettext("Files")}: </span>
<code class="font-mono break-all">{slug_file_pattern}</code>
</p>
<p>
<span class="font-medium text-base-content">
{gettext("Public URL")}:
</span>
<code class="font-mono break-all">{slug_url_pattern}</code>
</p>
</div>
</div>
</label>
</div>
<label class="label">
<span class="label-text-alt text-xs text-base-content/60">
{gettext(
"The storage mode locks in after creation to keep your structure consistent."
)}
</span>
</label>
</div>
<div class="flex flex-wrap gap-3 justify-end">
<button type="submit" class="btn btn-primary btn-sm">
<.icon name="hero-plus" class="w-4 h-4 mr-1" /> {gettext("Create Blog")}
</button>
<button type="button" class="btn btn-ghost btn-sm" phx-click="cancel">
<.icon name="hero-arrow-uturn-left" class="w-4 h-4 mr-1" /> {gettext("Cancel")}
</button>
</div>
</.form>
</div>
</div>
<div class="card bg-base-100 shadow-xl border border-base-200">
<div class="card-body space-y-3">
<h3 class="text-lg font-semibold text-base-content">
{gettext("What happens next")}
</h3>
<ul class="text-sm text-base-content/70 space-y-2">
<li>• {gettext("We create a blog workspace under priv/blogging.")}</li>
<li>• {gettext("You'll see the new blog in the navigation immediately.")}</li>
<li>• {gettext("Editors can jump right in and start drafting content.")}</li>
</ul>
</div>
</div>
</div>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>