Insert section (#114)

* Add section insertion button

* Add shortcut for inserting section

* Pass buttons to the component

* Add mix alias for running both formatter

* Adjustments

* Make the buttons group component stateless
This commit is contained in:
Jonatan Kłosko 2021-03-24 18:37:50 +01:00 committed by GitHub
parent 50db813092
commit fe5dfe3b86
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 77 additions and 42 deletions

View file

@ -5,7 +5,7 @@
}
.button:not(:disabled) {
@apply hover:bg-gray-50 focus:bg-gray-50;
@apply hover:bg-gray-100 focus:bg-gray-100;
}
.button:disabled {
@ -13,7 +13,7 @@
}
.button-sm {
@apply px-3 py-1;
@apply px-2 py-1;
}
.button-danger {

View file

@ -169,6 +169,8 @@ function handleDocumentKeyDown(hook, event) {
insertCellBelowFocused(hook, "markdown");
} else if (keyBuffer.tryMatch(["M"])) {
insertCellAboveFocused(hook, "markdown");
} else if (keyBuffer.tryMatch(["S"])) {
addSection(hook);
}
}
}
@ -380,6 +382,10 @@ function insertCellAboveFocused(hook, type) {
}
}
function addSection(hook) {
hook.pushEvent("add_section", {});
}
function insertFirstCell(hook, type) {
const sectionIds = getSectionIds();

View file

@ -0,0 +1,13 @@
defmodule LivebookWeb.InsertButtonsComponent do
use LivebookWeb, :live_component
def render(assigns) do
~L"""
<div class="relative top-0.5 m-0 flex justify-center">
<div class="absolute z-10 <%= if(@persistent, do: "opacity-100", else: "opacity-0") %> hover:opacity-100 focus-within:opacity-100 flex space-x-2 justify-center items-center">
<%= render_block(@inner_block) %>
</div>
</div>
"""
end
end

View file

@ -1,26 +0,0 @@
defmodule LivebookWeb.InsertCellComponent do
use LivebookWeb, :live_component
def render(assigns) do
~L"""
<div class="relative top-0.5 m-0 flex justify-center">
<div class="absolute z-10 <%= if(@persistent, do: "opacity-100", else: "opacity-0") %> hover:opacity-100 focus-within:opacity-100 flex space-x-2 justify-center items-center">
<button class="py-1 px-2 text-sm text-gray-600 font-medium rounded-lg border border-gray-200 bg-gray-50 hover:bg-gray-100 focus:bg-gray-100"
phx-click="insert_cell"
phx-value-type="markdown"
phx-value-section_id="<%= @section_id %>"
phx-value-index="<%= @index %>">
+ Markdown
</button>
<button class="py-1 px-2 text-sm text-gray-600 font-medium rounded-lg border border-gray-200 bg-gray-50 hover:bg-gray-100 focus:bg-gray-100"
phx-click="insert_cell"
phx-value-type="elixir"
phx-value-section_id="<%= @section_id %>"
phx-value-index="<%= @index %>">
+ Elixir
</button>
</div>
</div>
"""
end
end

View file

@ -26,22 +26,46 @@ defmodule LivebookWeb.SectionComponent do
</div>
<div class="container py-2">
<div class="flex flex-col space-y-1">
<%= live_component @socket, LivebookWeb.InsertCellComponent,
id: "#{@section.id}:0",
section_id: @section.id,
index: 0,
persistent: @section.cells == [] %>
<%= for {cell, index} <- Enum.with_index(@section.cells) do %>
<%= live_component @socket, LivebookWeb.InsertButtonsComponent,
persistent: false do %>
<button class="button button-sm"
phx-click="insert_cell"
phx-value-type="markdown"
phx-value-section_id="<%= @section.id %>"
phx-value-index="<%= index %>"
>+ Markdown</button>
<button class="button button-sm"
phx-click="insert_cell"
phx-value-type="elixir"
phx-value-section_id="<%= @section.id %>"
phx-value-index="<%= index %>"
>+ Elixir</button>
<% end %>
<%= live_component @socket, LivebookWeb.CellComponent,
id: cell.id,
session_id: @session_id,
cell: cell,
cell_info: @cell_infos[cell.id] %>
<%= live_component @socket, LivebookWeb.InsertCellComponent,
id: "#{@section.id}:#{index + 1}",
section_id: @section.id,
index: index + 1,
persistent: false %>
<% end %>
<%= live_component @socket, LivebookWeb.InsertButtonsComponent,
persistent: @section.cells == [] do %>
<button class="button button-sm"
phx-click="insert_cell"
phx-value-type="markdown"
phx-value-section_id="<%= @section.id %>"
phx-value-index="<%= length(@section.cells) %>"
>+ Markdown</button>
<button class="button button-sm"
phx-click="insert_cell"
phx-value-type="elixir"
phx-value-section_id="<%= @section.id %>"
phx-value-index="<%= length(@section.cells) %>"
>+ Elixir</button>
<button class="button button-sm"
phx-click="insert_section"
phx-value-index="<%= @index + 1 %>"
>+ Section</button>
<% end %>
</div>
</div>

View file

@ -83,14 +83,14 @@ defmodule LivebookWeb.SessionLive do
</span>
<span class="tooltip right distant" aria-label="Notebook settings (sn)">
<%= live_patch to: Routes.session_path(@socket, :settings, @session_id, "file"),
class: "text-gray-600 hover:text-gray-50 focus:text-gray-50 #{if(@live_action == :settings, do: "text-gray-50")}" do %>
class: "text-gray-600 hover:text-gray-50 focus:text-gray-50 #{if(@live_action == :settings, do: "text-gray-50")}" do %>
<%= remix_icon("settings-4-fill", class: "text-2xl") %>
<% end %>
</span>
<div class="flex-grow"></div>
<span class="tooltip right distant" aria-label="Keyboard shortcuts (?)">
<%= live_patch to: Routes.session_path(@socket, :shortcuts, @session_id),
class: "text-gray-600 hover:text-gray-50 focus:text-gray-50 #{if(@live_action == :shortcuts, do: "text-gray-50")}" do %>
class: "text-gray-600 hover:text-gray-50 focus:text-gray-50 #{if(@live_action == :shortcuts, do: "text-gray-50")}" do %>
<%= remix_icon("keyboard-box-fill", class: "text-2xl") %>
<% end %>
</span>
@ -125,9 +125,18 @@ defmodule LivebookWeb.SessionLive do
data-update-attribute="phx-value-name"><%= @data.notebook.name %></h1>
</div>
<div class="flex flex-col w-full space-y-16">
<%= for section <- @data.notebook.sections do %>
<%= if @data.notebook.sections == [] do %>
<div class="flex justify-center">
<button class="button button-sm"
phx-click="insert_section"
phx-value-index="0"
>+ Section</button>
</div>
<% end %>
<%= for {section, index} <- Enum.with_index(@data.notebook.sections) do %>
<%= live_component @socket, LivebookWeb.SectionComponent,
id: section.id,
index: index,
session_id: @session_id,
section: section,
cell_infos: @data.cell_infos %>
@ -183,6 +192,13 @@ defmodule LivebookWeb.SessionLive do
{:noreply, socket}
end
def handle_event("insert_section", %{"index" => index}, socket) do
index = ensure_integer(index) |> max(0)
Session.insert_section(socket.assigns.session_id, index)
{:noreply, socket}
end
def handle_event("delete_section", %{"section_id" => section_id}, socket) do
Session.delete_section(socket.assigns.session_id, section_id)

View file

@ -18,6 +18,7 @@ defmodule LivebookWeb.SessionLive.ShortcutsComponent do
%{seq: ["N"], desc: "Insert Elixir cell above"},
%{seq: ["M"], desc: "Insert Markdown cell above"},
%{seq: ["dd"], desc: "Delete cell"},
%{seq: ["S"], desc: "Add section"},
%{seq: ["ee"], desc: "Evaluate cell"},
%{seq: ["es"], desc: "Evaluate section"},
%{seq: ["ea"], desc: "Evaluate all stale/new cells"},

View file

@ -59,7 +59,8 @@ defmodule Livebook.MixProject do
setup: ["deps.get", "cmd npm install --prefix assets"],
# Update the assets bundle to be committed into the repository
# and also builds the Escript.
build: ["cmd npm run deploy --prefix ./assets", "escript.build"]
build: ["cmd npm run deploy --prefix ./assets", "escript.build"],
"format.all": ["format", "cmd npm run format --prefix ./assets"]
]
end