@@ -3,83 +3,109 @@ defmodule AtomicWeb.Components.ImageUploader do
33 An image uploader component that allows you to upload an image.
44 """
55
6- use AtomicWeb , :live_component
6+ use AtomicWeb , :component
7+
8+ attr :id , :string , default: "image-uploader"
9+ attr :upload , :any
10+ attr :class , :string , default: ""
11+ attr :image_class , :string , default: ""
12+ attr :image , :string , default: nil
13+ attr :icon , :string , default: "hero-photo"
14+ attr :preview_disabled , :boolean , default: false
15+ attr :rounded , :boolean , default: false
16+ attr :editable , :boolean , default: true
17+ attr :memory_unit , :string , default: "MB"
18+
19+ slot :placeholder , required: false , doc: "Slot for the placeholder content."
20+
21+ def image_uploader ( assigns ) do
22+ assigns = update ( assigns , % { } )
723
8- def render ( assigns ) do
924 ~H"""
1025 < div id = { @ id } >
11- < div class = " shrink-0 1.5xl:shrink-0 " >
26+ <%= if @ editable do % >
1227 < . live_file_input upload = { @ upload } class = "hidden " />
13- < div class = {
14- "#{ if length ( @ upload . entries ) != 0 do
15- "hidden"
16- end } #{ @ class } border-2 border-gray-300 border-dashed rounded-md"
17- } phx-drop-target = { @ upload . ref } >
18- < div class = "flex h-full items-center justify-center px-6 " >
19- < div class = "flex flex-col items-center justify-center space-y-1 " >
20- < . icon name = { @ icon } class = "size-8 text-zinc-400 " />
21- < div class = "flex flex-col items-center text-sm text-zinc-600 " >
22- < label for = "file-upload " class = "relative cursor-pointer rounded-md font-medium text-orange-500 hover:text-red-800 " >
23- < a onclick = { "document.getElementById('#{ @ upload . ref } ').click()" } > Upload a file</ a >
24- </ label >
25- < p class = "pl-1 " > or drag and drop</ p >
26- </ div >
27- < p class = "text-xs text-gray-500 " >
28- { extensions_to_string ( @ upload . accept ) } up to { assigns . size_file } { @ type }
29- </ p >
30- </ div >
31- </ div >
32- </ div >
33- < section >
28+ <% end %>
29+ < section
30+ phx-drop-target = { @ upload . ref }
31+ class = { [
32+ "hover:cursor-pointer" ,
33+ @ rounded && "rounded-full overflow-hidden" ,
34+ not @ rounded && "rounded-xl" ,
35+ @ class
36+ ] }
37+ onclick = { "document.getElementById('#{ @ upload . ref } ').click()" }
38+ >
39+ <%= if @ upload . entries == [ ] do %>
40+ < article class = "h-full " >
41+ < figure class = "flex h-full items-center justify-center " >
42+ <%= if @ image do %>
43+ < img class = { [ @ rounded && "p-0" , not @ rounded , @ image_class ] } src = { @ image } />
44+ <% else %>
45+ <%= if @ placeholder do %>
46+ < div class = "flex flex-col items-center gap-2 " >
47+ { render_slot ( @ placeholder ) }
48+ < p class = "text-xs text-gray-500 " >
49+ { extensions_to_string ( @ upload . accept ) } < br /> up to { @ size_file } { @ memory_unit }
50+ </ p >
51+ </ div >
52+ <% else %>
53+ < div class = "flex select-none flex-col items-center gap-2 " >
54+ < . icon name = { @ icon } class = "h-12 w-12 " />
55+ < p class = "px-4 text-center " > { gettext ( "Upload a file or drag and drop." ) } </ p >
56+ </ div >
57+ <% end %>
58+ <% end %>
59+ </ figure >
60+ </ article >
61+ <% end %>
62+ <%= if ! @ preview_disabled do %>
3463 <%= for entry <- @ upload . entries do %>
35- <%= for err <- upload_errors ( @ upload , entry ) do %>
36- < div class = "alert alert-danger relative rounded border border-red-400 bg-red-100 px-4 py-3 text-red-700 " role = "alert " >
37- < span class = "block sm:inline " > { Phoenix.Naming . humanize ( err ) } </ span >
38- < span class = "absolute top-0 right-0 bottom-0 px-4 py-3 " >
39- < title > Close</ title >
40- </ span >
41- </ div >
42- <% end %>
43- < article class = "upload-entry " >
44- < figure class = "w-[100px] " >
45- < . live_img_preview entry = { entry } id = { "preview-#{ entry . ref } " } class = "rounded-lg shadow-lg " />
46- < div class = "flex " >
47- < figcaption >
48- <%= if String . length ( entry . client_name ) < 30 do %>
49- { entry . client_name }
50- <% else %>
51- { String . slice ( entry . client_name , 0 .. 30 ) <> "... " }
52- <% end %>
53- </ figcaption >
54- < button type = "button " phx-click = "cancel-image " phx-target = { @ target } phx-value-ref = { entry . ref } aria-label = "cancel " class = "pl-4 " >
55- < . icon name = "hero-x-mark-solid " class = "size-5 text-zinc-400 " />
56- </ button >
57- </ div >
64+ < article class = "h-full " >
65+ < figure class = "flex h-full items-center justify-center " >
66+ <%= if entry . ref do %>
67+ < . live_img_preview id = { "preview-#{ entry . ref } " } class = { [ @ rounded && "p-0" , not @ rounded && "p-4" , @ image_class ] } entry = { entry } />
68+ <% else %>
69+ < div class = "flex select-none flex-col items-center gap-2 " >
70+ < . icon name = "hero-document " class = "h-12 w-12 " />
71+ < p class = "px-4 text-center " > { entry . client_name } </ p >
72+ </ div >
73+ <% end %>
5874 </ figure >
75+ <%= for err <- upload_errors ( @ upload , entry ) do %>
76+ < p class = "alert alert-danger " > { Phoenix.Naming . humanize ( err ) } </ p >
77+ <% end %>
5978 </ article >
6079 <% end %>
61- </ section >
62- </ div >
80+ <% end %>
81+ <%= for err <- upload_errors ( @ upload ) do %>
82+ < p class = "alert alert-danger " > { Phoenix.Naming . humanize ( err ) } </ p >
83+ <% end %>
84+ </ section >
6385 </ div >
6486 """
6587 end
6688
67- def update ( assigns , socket ) do
68- max_size = assigns . upload . max_file_size
69- type = assigns [ :type ]
89+ def update ( assigns , _socket ) do
90+ max_size =
91+ if Map . has_key? ( assigns , :upload ) do
92+ assigns . upload . max_file_size
93+ else
94+ 0
95+ end
96+
97+ memory_unit = assigns [ :memory_unit ]
7098
71- size_file = convert_size ( max_size , type )
99+ size_file = convert_size ( max_size , memory_unit )
72100
73- { :ok ,
74- socket
75- |> assign ( assigns )
76- |> assign ( :size_file , size_file ) }
101+ assigns
102+ |> Map . put ( :size_file , size_file )
77103 end
78104
79- defp convert_size ( size_in_bytes , type ) do
105+ defp convert_size ( size_in_bytes , memory_unit ) do
80106 size_in_bytes_float = size_in_bytes * 1.0
81107
82- case type do
108+ case memory_unit do
83109 "kB" -> Float . round ( size_in_bytes_float / 1_000 , 2 )
84110 "MB" -> Float . round ( size_in_bytes_float / 1_000_000 , 2 )
85111 "GB" -> Float . round ( size_in_bytes_float / 1_000_000_000 , 2 )
0 commit comments