mirror of
				https://github.com/livebook-dev/livebook.git
				synced 2025-10-25 21:06:08 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			99 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			Elixir
		
	
	
	
	
	
			
		
		
	
	
			99 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			Elixir
		
	
	
	
	
	
| defmodule LivebookWeb.SessionLive.CellUploadComponent do
 | |
|   use LivebookWeb, :live_component
 | |
| 
 | |
|   alias Livebook.FileSystem
 | |
| 
 | |
|   @impl true
 | |
|   def mount(socket) do
 | |
|     {:ok, assign(socket, name: "", error_message: nil)}
 | |
|   end
 | |
| 
 | |
|   @impl true
 | |
|   def render(assigns) do
 | |
|     ~H"""
 | |
|     <div class="p-6 flex flex-col space-y-8">
 | |
|       <h3 class="text-2xl font-semibold text-gray-800">
 | |
|         Insert image
 | |
|       </h3>
 | |
|       <div :if={@uploads.cell_image.errors != []} class="error-box">
 | |
|         Invalid image file. The image must be either GIF, JPEG, SVG or PNG and cannot exceed 5MB in size.
 | |
|       </div>
 | |
|       <div :if={@error_message} class="error-box">
 | |
|         <%= @error_message %>
 | |
|       </div>
 | |
|       <div :for={entry <- @uploads.cell_image.entries} class="flex flex-col space-y-1">
 | |
|         <div class="flex justify-between text-gray-700">
 | |
|           <span><%= entry.client_name %></span>
 | |
|           <span><%= entry.progress %>%</span>
 | |
|         </div>
 | |
|         <div class="w-full h-2 rounded-lg bg-blue-200">
 | |
|           <div
 | |
|             class="h-full rounded-lg bg-blue-600 transition-all ease-out duration-1000"
 | |
|             style={"width: #{entry.progress}%"}
 | |
|           >
 | |
|           </div>
 | |
|         </div>
 | |
|       </div>
 | |
|       <form phx-submit="save" phx-change="validate" phx-target={@myself}>
 | |
|         <div class="w-full flex space-x-2">
 | |
|           <div>
 | |
|             <label>
 | |
|               <.live_file_input upload={@uploads.cell_image} class="hidden" />
 | |
|               <div class="cursor-pointer button-base button-gray button-square-icon">
 | |
|                 <.remix_icon icon="folder-upload-line" />
 | |
|               </div>
 | |
|             </label>
 | |
|           </div>
 | |
|           <div class="grow">
 | |
|             <input class="input" name="name" value={@name} placeholder="Name" autocomplete="off" />
 | |
|           </div>
 | |
|         </div>
 | |
|         <div class="mt-8 flex justify-end space-x-2">
 | |
|           <.link patch={@return_to} class="button-base button-outlined-gray">
 | |
|             Cancel
 | |
|           </.link>
 | |
|           <button
 | |
|             class="button-base button-blue"
 | |
|             type="submit"
 | |
|             disabled={@uploads.cell_image.entries == []}
 | |
|           >
 | |
|             Upload
 | |
|           </button>
 | |
|         </div>
 | |
|       </form>
 | |
|     </div>
 | |
|     """
 | |
|   end
 | |
| 
 | |
|   @impl true
 | |
|   def handle_event("validate", %{"name" => name}, socket) do
 | |
|     {:noreply, assign(socket, name: name)}
 | |
|   end
 | |
| 
 | |
|   def handle_event("save", %{"name" => name}, socket) do
 | |
|     %{images_dir: images_dir} = socket.assigns.session
 | |
| 
 | |
|     consume_uploaded_entries(socket, :cell_image, fn %{path: path}, entry ->
 | |
|       upload_file = FileSystem.File.local(path)
 | |
|       ext = Path.extname(entry.client_name)
 | |
|       filename = if name == "", do: entry.client_name, else: name <> ext
 | |
|       destination_file = FileSystem.File.resolve(images_dir, filename)
 | |
| 
 | |
|       result =
 | |
|         with :ok <- FileSystem.File.copy(upload_file, destination_file) do
 | |
|           {:ok, filename}
 | |
|         end
 | |
| 
 | |
|       {:ok, result}
 | |
|     end)
 | |
|     |> case do
 | |
|       [{:ok, filename}] ->
 | |
|         url = "images/#{URI.encode(filename, &URI.char_unreserved?/1)}"
 | |
|         send(self(), {:cell_upload_complete, socket.assigns.cell_upload_metadata, url})
 | |
|         {:noreply, push_patch(socket, to: socket.assigns.return_to)}
 | |
| 
 | |
|       [{:error, message}] ->
 | |
|         {:noreply, assign(socket, error_message: message)}
 | |
|     end
 | |
|   end
 | |
| end
 |