"""
end
defp render_cell_anchor_link(assigns) do
~L"""
<%= remix_icon("link", class: "text-xl") %>
"""
end
# The whole page has to load and then hooks are mounded.
# There may be a tiny delay before the markdown is rendered
# or editors are mounted, so show neat placeholders immediately.
defp render_content_placeholder(_bg_class, true = _empty) do
assigns = %{}
~L"""
"""
end
defp render_content_placeholder(bg_class, false = _empty) do
assigns = %{bg_class: bg_class}
~L"""
"""
end
defp render_outputs(assigns, socket) do
~L"""
<%= for {output, index} <- @cell_view.outputs |> Enum.reverse() |> Enum.with_index(), output != :ignored do %>
"""
end
defp render_output(_socket, text, id) when is_binary(text) do
# Captured output usually has a trailing newline that we can ignore,
# because each line is itself an HTML block anyway.
text = String.replace_suffix(text, "\n", "")
live_component(LivebookWeb.Output.TextComponent, id: id, content: text, follow: true)
end
defp render_output(_socket, {:text, text}, id) do
live_component(LivebookWeb.Output.TextComponent, id: id, content: text, follow: false)
end
defp render_output(_socket, {:markdown, markdown}, id) do
live_component(LivebookWeb.Output.MarkdownComponent, id: id, content: markdown)
end
defp render_output(_socket, {:image, content, mime_type}, id) do
live_component(LivebookWeb.Output.ImageComponent,
id: id,
content: content,
mime_type: mime_type
)
end
defp render_output(_socket, {:vega_lite_static, spec}, id) do
live_component(LivebookWeb.Output.VegaLiteStaticComponent, id: id, spec: spec)
end
defp render_output(socket, {:vega_lite_dynamic, pid}, id) do
live_render(socket, LivebookWeb.Output.VegaLiteDynamicLive,
id: id,
session: %{"id" => id, "pid" => pid}
)
end
defp render_output(socket, {:table_dynamic, pid}, id) do
live_render(socket, LivebookWeb.Output.TableDynamicLive,
id: id,
session: %{"id" => id, "pid" => pid}
)
end
defp render_output(_socket, {:error, formatted}, _id) do
render_error_message_output(formatted)
end
defp render_output(_socket, output, _id) do
render_error_message_output("""
Unknown output format: #{inspect(output)}. If you're using Kino,
you may want to update Kino and Livebook to the latest version.
""")
end
defp render_error_message_output(message) do
assigns = %{message: message}
~L"""
<%= @message %>
"""
end
defp render_cell_status(cell_view, evaluation_status, evaluation_time_ms, evaluation_id)
defp render_cell_status(_, :evaluating, _, evaluation_id) do
timer =
content_tag(:span, nil,
phx_hook: "Timer",
# Make sure each evaluation gets its own timer
id: "#{evaluation_id}-timer",
phx_update: "ignore",
class: "font-mono"
)
render_status_indicator(timer, "bg-blue-500",
animated_circle_class: "bg-blue-400",
change_indicator: true
)
end
defp render_cell_status(_, :queued, _, _) do
render_status_indicator("Queued", "bg-gray-500", animated_circle_class: "bg-gray-400")
end
defp render_cell_status(:evaluated, _, evaluation_time_ms, _) do
render_status_indicator("Evaluated", "bg-green-400",
change_indicator: true,
tooltip: evaluated_label(evaluation_time_ms)
)
end
defp render_cell_status(:stale, _, evaluation_time_ms, _) do
render_status_indicator("Stale", "bg-yellow-200",
change_indicator: true,
tooltip: evaluated_label(evaluation_time_ms)
)
end
defp render_cell_status(:aborted, _, _, _) do
render_status_indicator("Aborted", "bg-red-400")
end
defp render_cell_status(_, _, _, _), do: nil
defp render_status_indicator(element, circle_class, opts \\ []) do
assigns = %{
element: element,
circle_class: circle_class,
animated_circle_class: Keyword.get(opts, :animated_circle_class),
change_indicator: Keyword.get(opts, :change_indicator, false),
tooltip: Keyword.get(opts, :tooltip)
}
~L"""
<%= @element %>
<%= if @change_indicator do %>
*
<% end %>
<%= if @animated_circle_class do %>
<% end %>
"""
end
defp evaluated_label(time_ms) when is_integer(time_ms) do
evaluation_time =
if time_ms > 100 do
seconds = time_ms |> Kernel./(1000) |> Float.floor(1)
"#{seconds}s"
else
"#{time_ms}ms"
end
"Took " <> evaluation_time
end
defp evaluated_label(_time_ms), do: nil
end