Packages
livebook
0.10.0
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.14.0-rc.1
0.14.0-rc.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Automate code & data workflows with interactive notebooks
Current section
Files
Jump to
Current section
Files
lib/livebook_web/live/session_live/insert_buttons_component.ex
defmodule LivebookWeb.SessionLive.InsertButtonsComponent do
use LivebookWeb, :live_component
import LivebookWeb.SessionHelpers
defguardp is_many(list) when tl(list) != []
def render(assigns) do
~H"""
<div
class="relative top-0.5 m-0 flex justify-center"
role="toolbar"
aria-label="insert new"
data-el-insert-buttons
>
<div class={
"w-full md:absolute z-10 hover:z-[11] #{if(@persistent, do: "opacity-100", else: "opacity-0")} hover:opacity-100 focus-within:opacity-100 flex space-x-2 justify-center items-center"
}>
<.menu id={"cell-#{@id}-insert"} position={:bottom_left} distant>
<:toggle>
<button class="button-base button-small flex items-center pr-1">
<div
class="pr-2"
phx-click="insert_cell_below"
phx-value-type="code"
phx-value-section_id={@section_id}
phx-value-cell_id={@cell_id}
>
+ <%= @default_language |> Atom.to_string() |> String.capitalize() %>
</div>
<div class="pl-1 flex items-center border-l border-gray-200">
<.remix_icon icon="arrow-down-s-line" class="text-lg leading-none" />
</div>
</button>
</:toggle>
<.menu_item>
<button
role="menuitem"
phx-click="set_default_language"
phx-value-type="code"
phx-value-language="elixir"
phx-value-section_id={@section_id}
phx-value-cell_id={@cell_id}
>
<.cell_icon cell_type={:code} language={:elixir} />
<span>Elixir</span>
</button>
</.menu_item>
<.menu_item>
<button
role="menuitem"
phx-click="set_default_language"
phx-value-type="code"
phx-value-language="erlang"
phx-value-section_id={@section_id}
phx-value-cell_id={@cell_id}
>
<.cell_icon cell_type={:code} language={:erlang} />
<span>Erlang</span>
</button>
</.menu_item>
</.menu>
<.menu id={"#{@id}-block-menu"} position={:bottom_left}>
<:toggle>
<button class="button-base button-small">+ Block</button>
</:toggle>
<.menu_item>
<button
role="menuitem"
phx-click="insert_cell_below"
phx-value-type="markdown"
phx-value-section_id={@section_id}
phx-value-cell_id={@cell_id}
>
<.remix_icon icon="markdown-fill" />
<span>Markdown</span>
</button>
</.menu_item>
<.menu_item>
<button
role="menuitem"
phx-click="insert_section_below"
phx-value-section_id={@section_id}
phx-value-cell_id={@cell_id}
>
<.remix_icon icon="h-2" />
<span>Section</span>
</button>
</.menu_item>
<div class="flex items-center mt-4 mb-1 px-5 text-xs text-gray-400 font-light">
MARKDOWN
</div>
<.menu_item>
<button
role="menuitem"
phx-click="insert_cell_below"
phx-value-type="diagram"
phx-value-section_id={@section_id}
phx-value-cell_id={@cell_id}
>
<.remix_icon icon="organization-chart" />
<span>Diagram</span>
</button>
</.menu_item>
<.menu_item>
<.link
patch={
~p"/sessions/#{@session_id}/cell-upload?section_id=#{@section_id}&cell_id=#{@cell_id || ""}"
}
aria-label="insert image"
role="menuitem"
>
<.remix_icon icon="image-add-line" />
<span>Image</span>
</.link>
</.menu_item>
<%= if @code_block_definitions != [] do %>
<div class="flex items-center mt-4 mb-1 px-5 text-xs text-gray-400 font-light">
CODE
</div>
<.menu_item :for={definition <- Enum.sort_by(@code_block_definitions, & &1.name)}>
<.code_block_insert_button
definition={definition}
runtime={@runtime}
section_id={@section_id}
cell_id={@cell_id}
/>
</.menu_item>
<% end %>
</.menu>
<%= cond do %>
<% not Livebook.Runtime.connected?(@runtime) -> %>
<button
class="button-base button-small"
phx-click={
JS.push("setup_default_runtime",
value: %{reason: "To see the available smart cells, you need a connected runtime."}
)
}
>
+ Smart
</button>
<% @smart_cell_definitions == [] -> %>
<span class="tooltip right" data-tooltip="No smart cells available">
<button class="button-base button-small" disabled>+ Smart</button>
</span>
<% true -> %>
<.menu id={"#{@id}-smart-menu"} position={:bottom_left}>
<:toggle>
<button class="button-base button-small">+ Smart</button>
</:toggle>
<.menu_item :for={definition <- Enum.sort_by(@smart_cell_definitions, & &1.name)}>
<.smart_cell_insert_button
definition={definition}
section_id={@section_id}
cell_id={@cell_id}
/>
</.menu_item>
</.menu>
<% end %>
</div>
</div>
"""
end
defp code_block_insert_button(assigns) when is_many(assigns.definition.variants) do
~H"""
<.submenu>
<:primary>
<button role="menuitem">
<.remix_icon icon={@definition.icon} />
<span><%= @definition.name %></span>
</button>
</:primary>
<.menu_item :for={{variant, idx} <- Enum.with_index(@definition.variants)}>
<button
role="menuitem"
phx-click={on_code_block_click(@definition, idx, @runtime, @section_id, @cell_id)}
>
<span><%= variant.name %></span>
</button>
</.menu_item>
</.submenu>
"""
end
defp code_block_insert_button(assigns) do
~H"""
<button
role="menuitem"
phx-click={on_code_block_click(@definition, 0, @runtime, @section_id, @cell_id)}
>
<.remix_icon icon={@definition.icon} />
<span><%= @definition.name %></span>
</button>
"""
end
defp smart_cell_insert_button(assigns) when is_many(assigns.definition.requirement_presets) do
~H"""
<.submenu>
<:primary>
<button role="menuitem">
<span><%= @definition.name %></span>
</button>
</:primary>
<.menu_item :for={{preset, idx} <- Enum.with_index(@definition.requirement_presets)}>
<button
role="menuitem"
phx-click={on_smart_cell_click(@definition, idx, @section_id, @cell_id)}
>
<span><%= preset.name %></span>
</button>
</.menu_item>
</.submenu>
"""
end
defp smart_cell_insert_button(assigns) do
~H"""
<button role="menuitem" phx-click={on_smart_cell_click(@definition, @section_id, @cell_id)}>
<span><%= @definition.name %></span>
</button>
"""
end
defp on_code_block_click(definition, variant_idx, runtime, section_id, cell_id) do
if Livebook.Runtime.connected?(runtime) do
JS.push("insert_code_block_below",
value: %{
definition_name: definition.name,
variant_idx: variant_idx,
section_id: section_id,
cell_id: cell_id
}
)
else
JS.push("setup_default_runtime",
value: %{reason: "To insert this block, you need a connected runtime."}
)
end
end
defp on_smart_cell_click(definition, section_id, cell_id) do
preset_idx = if definition.requirement_presets == [], do: nil, else: 0
on_smart_cell_click(definition, preset_idx, section_id, cell_id)
end
defp on_smart_cell_click(definition, preset_idx, section_id, cell_id) do
JS.push("insert_smart_cell_below",
value: %{
kind: definition.kind,
section_id: section_id,
cell_id: cell_id,
preset_idx: preset_idx
}
)
end
end