@@ -3,83 +3,109 @@ defmodule AtomicWeb.Components.ImageUploader do
3
3
An image uploader component that allows you to upload an image.
4
4
"""
5
5
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 , % { } )
7
23
8
- def render ( assigns ) do
9
24
~H"""
10
25
< div id = { @ id } >
11
- < div class = " shrink-0 1.5xl:shrink-0 " >
26
+ <%= if @ editable do % >
12
27
< . 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 %>
34
63
<%= 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 %>
58
74
</ figure >
75
+ <%= for err <- upload_errors ( @ upload , entry ) do %>
76
+ < p class = "alert alert-danger " > { Phoenix.Naming . humanize ( err ) } </ p >
77
+ <% end %>
59
78
</ article >
60
79
<% 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 >
63
85
</ div >
64
86
"""
65
87
end
66
88
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 ]
70
98
71
- size_file = convert_size ( max_size , type )
99
+ size_file = convert_size ( max_size , memory_unit )
72
100
73
- { :ok ,
74
- socket
75
- |> assign ( assigns )
76
- |> assign ( :size_file , size_file ) }
101
+ assigns
102
+ |> Map . put ( :size_file , size_file )
77
103
end
78
104
79
- defp convert_size ( size_in_bytes , type ) do
105
+ defp convert_size ( size_in_bytes , memory_unit ) do
80
106
size_in_bytes_float = size_in_bytes * 1.0
81
107
82
- case type do
108
+ case memory_unit do
83
109
"kB" -> Float . round ( size_in_bytes_float / 1_000 , 2 )
84
110
"MB" -> Float . round ( size_in_bytes_float / 1_000_000 , 2 )
85
111
"GB" -> Float . round ( size_in_bytes_float / 1_000_000_000 , 2 )
0 commit comments