Packages
livebook
0.14.4
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.NotebookComponents
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="absolute inset-0 h-[30px] z-[100] bg-white rounded-lg border-2 border-dashed border-gray-400"
data-el-insert-drop-area
data-section-id={@section_id}
data-cell-id={@cell_id}
id={"cell-#{@id}-dropzone"}
phx-hook="Dropzone"
>
</div>
<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>
<.insert_button>
<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="-mr-1 pl-1 flex items-center border-l border-gray-200 group-hover:border-gray-300 group-focus:border-gray-300">
<.remix_icon icon="arrow-down-s-line" class="text-lg leading-none" />
</div>
</.insert_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>
<.insert_button>+ Block</.insert_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>
<.menu_item>
<button
role="menuitem"
phx-click="insert_branching_section_below"
phx-value-section_id={@section_id}
phx-value-cell_id={@cell_id}
>
<.remix_icon icon="git-branch-line" />
<span>Branching 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>
<button
phx-click="insert_image"
phx-value-section_id={@section_id}
phx-value-cell_id={@cell_id}
aria-label="insert image"
role="menuitem"
>
<.remix_icon icon="image-add-line" />
<span>Image</span>
</button>
</.menu_item>
<%= if @example_snippet_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 <- @example_snippet_definitions}>
<.example_snippet_insert_button
definition={definition}
section_id={@section_id}
cell_id={@cell_id}
/>
</.menu_item>
<% end %>
</.menu>
<%= cond do %>
<% @runtime_status == :disconnected -> %>
<.insert_button phx-click={
JS.push("setup_runtime",
value: %{reason: "To see the available smart cells, you need a connected runtime."}
)
}>
+ Smart
</.insert_button>
<% @smart_cell_definitions == [] -> %>
<span class="tooltip right" data-tooltip="No smart cells available">
<.insert_button disabled>+ Smart</.insert_button>
</span>
<% true -> %>
<.menu id={"#{@id}-smart-menu"} position={:bottom_left}>
<:toggle>
<.insert_button>+ Smart</.insert_button>
</:toggle>
<.menu_item :for={definition <- @smart_cell_definitions}>
<.smart_cell_insert_button
definition={definition}
section_id={@section_id}
cell_id={@cell_id}
/>
</.menu_item>
</.menu>
<% end %>
</div>
</div>
"""
end
attr :disabled, :boolean, default: false
attr :rest, :global
slot :inner_block
def insert_button(assigns) do
~H"""
<button
{@rest}
class={[
"inline-flex items-center px-2 py-1 rounded-lg font-medium text-sm whitespace-nowrap border",
if @disabled do
"cursor-default pointer-events-none border-transparent bg-gray-100 text-gray-400"
else
"bg-gray-50 border-gray-200 text-gray-600 hover:bg-gray-100 focus:bg-gray-100"
end
]}
>
<%= render_slot(@inner_block) %>
</button>
"""
end
defp example_snippet_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_example_snippet_click(@definition, idx, @section_id, @cell_id)}
>
<span><%= variant.name %></span>
</button>
</.menu_item>
</.submenu>
"""
end
defp example_snippet_insert_button(assigns) do
~H"""
<button
role="menuitem"
phx-click={on_example_snippet_click(@definition, 0, @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_example_snippet_click(definition, variant_idx, section_id, cell_id) do
JS.push("insert_example_snippet_below",
value: %{
definition_name: definition.name,
variant_idx: variant_idx,
section_id: section_id,
cell_id: cell_id
}
)
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