Packages
phoenix_kit
1.7.21
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/users/media.html.heex
<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title="Media"
current_path={@url_path}
project_title={@project_title}
current_locale={@current_locale}
>
<div class="p-6">
<div class="mb-8">
<h1 class="text-3xl font-bold text-base-content">Media</h1>
<p class="text-base-content/70 mt-1">Manage user media and uploads</p>
</div>
<%!-- Upload Section (Hidden by default) --%>
<%= if @show_upload do %>
<div class="card bg-base-100 shadow-xl mb-8 animate-in fade-in duration-200">
<div class="card-body">
<div class="flex items-center gap-3 mb-4">
<h2 class="card-title text-xl">Upload Media</h2>
<button
phx-click="toggle_upload"
class="btn btn-sm btn-error gap-2"
>
<.icon name="hero-x-mark" class="w-4 h-4" /> Cancel
</button>
</div>
<%= if @has_buckets do %>
<p class="text-sm text-base-content/70 mb-4">
Upload images, videos, or PDFs. Files are automatically processed and optimized.
</p>
<.file_upload
upload={@uploads.media_files}
label="Upload Media Files"
icon="hero-cloud-arrow-up"
accept_description="JPG, PNG, WebP, MP4, WebM, PDF"
max_size_description="100MB per file"
/>
<% else %>
<div class="alert alert-warning">
<.icon name="hero-exclamation-triangle" class="stroke-current shrink-0 h-6 w-6" />
<div>
<h3 class="font-bold">No Storage Buckets Configured</h3>
<div class="text-sm mt-1">
You need to configure at least one storage bucket before you can upload files.
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/media")}
class="link link-primary font-semibold"
>
Configure Storage Buckets
</.link>
</div>
</div>
</div>
<% end %>
</div>
</div>
<% end %>
<%!-- Uploaded Files --%>
<%= if @total_count > 0 do %>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<div class="flex justify-between items-center mb-4">
<div class="flex items-center gap-3">
<h2 class="card-title text-xl">Uploaded Files ({@total_count})</h2>
<%= unless @show_upload do %>
<button
phx-click="toggle_upload"
class="btn btn-sm btn-primary gap-2"
>
<.icon name="hero-plus" class="w-4 h-4" /> Add Media
</button>
<% end %>
</div>
<.pagination_info
page={@current_page}
per_page={@per_page}
total_count={@total_count}
/>
</div>
<div class="grid grid-cols-3 md:grid-cols-5 lg:grid-cols-6 gap-3">
<%= for file <- @uploaded_files do %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/media/#{file.file_id}")}
class="group relative aspect-square bg-base-300 rounded-lg overflow-hidden cursor-pointer hover:shadow-lg transition-shadow"
>
<% image_url =
if file.file_type == "video" do
file.urls["video_thumbnail"]
else
file.urls["medium"] || file.urls["thumbnail"] || file.urls["original"]
end %>
<%= if image_url do %>
<img
src={image_url}
alt={file.filename}
class="w-full h-full object-cover pointer-events-none group-hover:opacity-75 transition-opacity"
onerror="this.parentElement.querySelector('.image-error-placeholder').style.display='grid';"
/>
<div class="image-error-placeholder hidden absolute inset-0 bg-base-300 grid place-items-center text-base-content/50">
<div class="flex flex-col items-center justify-center">
<.icon name="hero-photo" class="w-12 h-12 mb-2 text-error" />
<p class="text-xs font-semibold">Image Missing</p>
</div>
</div>
<% else %>
<div class="flex flex-col items-center justify-center w-full h-full text-base-content/50 group-hover:bg-base-200 transition-colors">
<.icon name={file_icon(file.file_type)} class="w-12 h-12 mb-2" />
<p class="text-sm font-semibold">{String.upcase(file.file_type)}</p>
</div>
<% end %>
<%!-- Video indicator icon --%>
<%= if file.file_type == "video" do %>
<div class="absolute top-2 left-2 bg-black/60 text-white p-1.5 rounded pointer-events-none flex items-center justify-center">
<.icon name="hero-play-solid" class="w-4 h-4" />
</div>
<% end %>
<%!-- File size in corner --%>
<div class="absolute bottom-2 right-2 bg-black/60 text-white text-xs px-2 py-1 rounded pointer-events-none">
{format_file_size(file.size)}
</div>
</.link>
<% end %>
</div>
<%!-- Pagination Controls --%>
<%= if @total_count > @per_page do %>
<.pagination
current_page={@current_page}
total_pages={@total_pages}
base_path={@url_path}
/>
<% end %>
</div>
</div>
<% else %>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<div class="flex items-center gap-3 mb-4">
<h2 class="card-title text-xl">Uploaded Files</h2>
<button
phx-click="toggle_upload"
class={["btn btn-sm gap-2", (@show_upload && "btn-error") || "btn-primary"]}
>
<%= if @show_upload do %>
<.icon name="hero-x-mark" class="w-4 h-4" /> Cancel
<% else %>
<.icon name="hero-plus" class="w-4 h-4" /> Add Media
<% end %>
</button>
</div>
<div class="bg-base-200 rounded-lg p-8 text-center">
<p class="text-base-content/70">
No media uploaded yet. Upload your first file above!
</p>
</div>
</div>
</div>
<% end %>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>