diff --git a/assets/css/components.css b/assets/css/components.css
index c52dbd91c..8533f6cba 100644
--- a/assets/css/components.css
+++ b/assets/css/components.css
@@ -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 {
diff --git a/assets/js/session/index.js b/assets/js/session/index.js
index ee68343c0..7f0cc930b 100644
--- a/assets/js/session/index.js
+++ b/assets/js/session/index.js
@@ -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();
diff --git a/lib/livebook_web/live/insert_buttons_component.ex b/lib/livebook_web/live/insert_buttons_component.ex
new file mode 100644
index 000000000..9639dcd41
--- /dev/null
+++ b/lib/livebook_web/live/insert_buttons_component.ex
@@ -0,0 +1,13 @@
+defmodule LivebookWeb.InsertButtonsComponent do
+ use LivebookWeb, :live_component
+
+ def render(assigns) do
+ ~L"""
+
+
hover:opacity-100 focus-within:opacity-100 flex space-x-2 justify-center items-center">
+ <%= render_block(@inner_block) %>
+
+
+ """
+ end
+end
diff --git a/lib/livebook_web/live/insert_cell_component.ex b/lib/livebook_web/live/insert_cell_component.ex
deleted file mode 100644
index c8ef66da9..000000000
--- a/lib/livebook_web/live/insert_cell_component.ex
+++ /dev/null
@@ -1,26 +0,0 @@
-defmodule LivebookWeb.InsertCellComponent do
- use LivebookWeb, :live_component
-
- def render(assigns) do
- ~L"""
-
-
hover:opacity-100 focus-within:opacity-100 flex space-x-2 justify-center items-center">
-
-
-
-
- """
- end
-end
diff --git a/lib/livebook_web/live/section_component.ex b/lib/livebook_web/live/section_component.ex
index 529b91f0e..f1842f250 100644
--- a/lib/livebook_web/live/section_component.ex
+++ b/lib/livebook_web/live/section_component.ex
@@ -26,22 +26,46 @@ defmodule LivebookWeb.SectionComponent do
- <%= 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 %>
+
+
+ <% 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 %>
+
+
+
<% end %>
diff --git a/lib/livebook_web/live/session_live.ex b/lib/livebook_web/live/session_live.ex
index f06051f38..c099df816 100644
--- a/lib/livebook_web/live/session_live.ex
+++ b/lib/livebook_web/live/session_live.ex
@@ -83,14 +83,14 @@ defmodule LivebookWeb.SessionLive do
<%= 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 %>
<%= 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 %>
@@ -125,9 +125,18 @@ defmodule LivebookWeb.SessionLive do
data-update-attribute="phx-value-name"><%= @data.notebook.name %>
- <%= for section <- @data.notebook.sections do %>
+ <%= if @data.notebook.sections == [] do %>
+
+
+
+ <% 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)
diff --git a/lib/livebook_web/live/session_live/shortcuts_component.ex b/lib/livebook_web/live/session_live/shortcuts_component.ex
index 6a58ea243..d338fbf39 100644
--- a/lib/livebook_web/live/session_live/shortcuts_component.ex
+++ b/lib/livebook_web/live/session_live/shortcuts_component.ex
@@ -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"},
diff --git a/mix.exs b/mix.exs
index 3d493a6d8..ffdbe6b26 100644
--- a/mix.exs
+++ b/mix.exs
@@ -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