mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-09-07 13:34:55 +08:00
parent
2694007c0e
commit
fbef386aa8
5 changed files with 118 additions and 0 deletions
|
@ -24,6 +24,7 @@ import Timer from "./timer";
|
|||
import MarkdownRenderer from "./markdown_renderer";
|
||||
import Highlight from "./highlight";
|
||||
import ClipCopy from "./clip_copy";
|
||||
import DragAndDrop from "./darg_and_drop";
|
||||
import morphdomCallbacks from "./morphdom_callbacks";
|
||||
import { loadUserData } from "./lib/user";
|
||||
|
||||
|
@ -41,6 +42,7 @@ const hooks = {
|
|||
MarkdownRenderer,
|
||||
Highlight,
|
||||
ClipCopy,
|
||||
DragAndDrop,
|
||||
};
|
||||
|
||||
const csrfToken = document
|
||||
|
|
25
assets/js/darg_and_drop/index.js
Normal file
25
assets/js/darg_and_drop/index.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
const DragAndDrop = {
|
||||
mounted() {
|
||||
const dropZone = this.el.querySelector("[data-dropzone]");
|
||||
|
||||
["dragenter", "dragover"].forEach((eventName) => {
|
||||
dropZone.addEventListener(eventName, highlight, false);
|
||||
});
|
||||
|
||||
["dragleave", "drop"].forEach((eventName) => {
|
||||
dropZone.addEventListener(eventName, unhighlight, false);
|
||||
});
|
||||
|
||||
function highlight(e) {
|
||||
dropZone.classList.add("bg-red-200");
|
||||
dropZone.classList.add("border-red-400");
|
||||
}
|
||||
|
||||
function unhighlight(e) {
|
||||
dropZone.classList.remove("bg-red-200");
|
||||
dropZone.classList.remove("border-red-400");
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default DragAndDrop;
|
|
@ -14,6 +14,11 @@ config :logger, :console,
|
|||
# Use Jason for JSON parsing in Phoenix
|
||||
config :phoenix, :json_library, Jason
|
||||
|
||||
# Add mime type to upload notebooks with `Phoenix.LiveView.Upload`
|
||||
config :mime, :types, %{
|
||||
"text/plain" => ["livemd"]
|
||||
}
|
||||
|
||||
# Sets the default authentication mode to token
|
||||
config :livebook, :authentication_mode, :token
|
||||
|
||||
|
|
|
@ -23,6 +23,13 @@ defmodule LivebookWeb.HomeLive.ImportComponent do
|
|||
From clipboard
|
||||
</span>
|
||||
<% end %>
|
||||
<%= live_patch to: Routes.home_path(@socket, :import, "file_upload"),
|
||||
class: "tab #{if(@tab == "file_upload", do: "active")}" do %>
|
||||
<.remix_icon icon="file-upload-line" class="align-middle" />
|
||||
<span class="font-medium">
|
||||
File upload
|
||||
</span>
|
||||
<% end %>
|
||||
<div class="flex-grow tab">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -35,4 +42,5 @@ defmodule LivebookWeb.HomeLive.ImportComponent do
|
|||
|
||||
defp component_for_tab("url"), do: LivebookWeb.HomeLive.ImportUrlComponent
|
||||
defp component_for_tab("content"), do: LivebookWeb.HomeLive.ImportContentComponent
|
||||
defp component_for_tab("file_upload"), do: LivebookWeb.HomeLive.ImportFileUploadComponent
|
||||
end
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
defmodule LivebookWeb.HomeLive.ImportFileUploadComponent do
|
||||
use LivebookWeb, :live_component
|
||||
|
||||
@impl true
|
||||
def mount(socket) do
|
||||
{:ok,
|
||||
socket
|
||||
|> assign(:error, false)
|
||||
|> allow_upload(:notebook, accept: ~w(.livemd), max_entries: 1)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div class="flex-col space-y-5">
|
||||
<p class="text-gray-700">
|
||||
Drag and drop a <code>.livemd</code> file below to import it.
|
||||
</p>
|
||||
<form id="upload-file-form"
|
||||
phx-submit="save"
|
||||
phx-change="validate"
|
||||
phx-drop-target={@uploads.notebook.ref}
|
||||
phx-target={@myself}
|
||||
phx-hook="DragAndDrop"
|
||||
class="flex flex-col items-start"
|
||||
>
|
||||
<%= live_file_input @uploads.notebook, class: "hidden" %>
|
||||
<div data-dropzone class="flex flex-col justify-center items-center w-full rounded-xl border-2 border-dashed border-gray-400 h-48">
|
||||
<%= if @uploads.notebook.entries == [] do %>
|
||||
<span name="placeholder" class="font-medium text-gray-400">Drop your notebook here</span>
|
||||
<% else %>
|
||||
<%= for file <- @uploads.notebook.entries do %>
|
||||
<div class="flex items-center">
|
||||
<span class="font-medium text-gray-400"><%= file.client_name %></span>
|
||||
<button type="button" class="icon-button" phx-click="clear-file" phx-target={@myself} tabindex="-1">
|
||||
<.remix_icon icon="close-line" class="text-xl text-gray-300 hover:text-gray-500" />
|
||||
</button>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= if @error do %>
|
||||
<div class="text-red-500 text-sm py-2">
|
||||
You can only upload files with .livemd extension.
|
||||
</div>
|
||||
<% end %>
|
||||
<button type="submit" class="mt-5 button button-blue" disabled={@uploads.notebook.entries == [] || @error}>
|
||||
Import
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
@impl Phoenix.LiveComponent
|
||||
def handle_event("clear-file", _params, socket) do
|
||||
{socket, _entries} = Phoenix.LiveView.Upload.maybe_cancel_uploads(socket)
|
||||
{:noreply, assign(socket, error: false)}
|
||||
end
|
||||
|
||||
@impl Phoenix.LiveComponent
|
||||
def handle_event("validate", _params, socket) do
|
||||
has_error? = Enum.any?(socket.assigns.uploads.notebook.entries, &(not &1.valid?))
|
||||
|
||||
{:noreply, assign(socket, error: has_error?)}
|
||||
end
|
||||
|
||||
@impl Phoenix.LiveComponent
|
||||
def handle_event("save", _params, socket) do
|
||||
consume_uploaded_entries(socket, :notebook, fn %{path: path}, _entry ->
|
||||
content = File.read!(path)
|
||||
|
||||
send(self(), {:import_content, content, []})
|
||||
end)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue