mirror of
https://github.com/livebook-dev/livebook.git
synced 2024-12-26 09:22:00 +08:00
Change anchor tags for sections to be based on the titles, not randomly generated (#288)
* Change anchor tags for sections to be based on the titles, not randomly generated * Update lib/livebook_web/helpers.ex Co-authored-by: Jonatan Kłosko <jonatanklosko@gmail.com>
This commit is contained in:
parent
e10f43e5b5
commit
8dfe12da68
4 changed files with 99 additions and 9 deletions
|
@ -86,4 +86,32 @@ defmodule LivebookWeb.Helpers do
|
|||
pid_str = Phoenix.LiveDashboard.Helpers.encode_pid(pid)
|
||||
Routes.live_dashboard_path(socket, :page, node(), "processes", info: pid_str)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Converts human-readable strings to strings which can be used
|
||||
as HTML element IDs (compatible with HTML5)
|
||||
|
||||
At the same time duplicate IDs are enumerated to avoid duplicates
|
||||
"""
|
||||
@spec names_to_html_ids(list(String.t())) :: list(String.t())
|
||||
def names_to_html_ids(names) do
|
||||
names
|
||||
|> Enum.map(&name_to_html_id/1)
|
||||
|> Enum.map_reduce(%{}, fn html_id, counts ->
|
||||
counts = Map.update(counts, html_id, 1, &(&1 + 1))
|
||||
|
||||
case counts[html_id] do
|
||||
1 -> {html_id, counts}
|
||||
count -> {"#{html_id}-#{count}", counts}
|
||||
end
|
||||
end)
|
||||
|> elem(0)
|
||||
end
|
||||
|
||||
defp name_to_html_id(name) do
|
||||
name
|
||||
|> String.trim()
|
||||
|> String.downcase()
|
||||
|> String.replace(~r/\s+/u, "-")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -737,7 +737,7 @@ defmodule LivebookWeb.SessionLive do
|
|||
data.clients_map
|
||||
|> Enum.map(fn {client_pid, user_id} -> {client_pid, data.users_map[user_id]} end)
|
||||
|> Enum.sort_by(fn {_client_pid, user} -> user.name end),
|
||||
section_views: Enum.map(data.notebook.sections, §ion_to_view(&1, data))
|
||||
section_views: section_views(data.notebook.sections, data)
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -768,12 +768,19 @@ defmodule LivebookWeb.SessionLive do
|
|||
|
||||
defp evaluated?(cell, data), do: data.cell_infos[cell.id].validity_status == :evaluated
|
||||
|
||||
defp section_to_view(section, data) do
|
||||
%{
|
||||
id: section.id,
|
||||
name: section.name,
|
||||
cell_views: Enum.map(section.cells, &cell_to_view(&1, data))
|
||||
}
|
||||
defp section_views(sections, data) do
|
||||
sections
|
||||
|> Enum.map(& &1.name)
|
||||
|> names_to_html_ids()
|
||||
|> Enum.zip(sections)
|
||||
|> Enum.map(fn {html_id, section} ->
|
||||
%{
|
||||
id: section.id,
|
||||
html_id: html_id,
|
||||
name: section.name,
|
||||
cell_views: Enum.map(section.cells, &cell_to_view(&1, data))
|
||||
}
|
||||
end)
|
||||
end
|
||||
|
||||
defp cell_to_view(cell, data) do
|
||||
|
|
|
@ -4,7 +4,7 @@ defmodule LivebookWeb.SessionLive.SectionComponent do
|
|||
def render(assigns) do
|
||||
~L"""
|
||||
<div
|
||||
id="section-<%= @section_view.id %>"
|
||||
id="<%= @section_view.html_id %>"
|
||||
data-element="section"
|
||||
data-section-id="<%= @section_view.id %>">
|
||||
<div class="flex space-x-4 items-center" data-element="section-headline">
|
||||
|
@ -21,7 +21,7 @@ defmodule LivebookWeb.SessionLive.SectionComponent do
|
|||
because we want the content to exactly match section name. %>
|
||||
<div class="flex space-x-2 items-center" data-element="section-actions">
|
||||
<span class="tooltip top" aria-label="Link">
|
||||
<a href="#section-<%= @section_view.id %>" class="icon-button">
|
||||
<a href="#<%= @section_view.html_id %>" class="icon-button">
|
||||
<%= remix_icon("link", class: "text-xl") %>
|
||||
</a>
|
||||
</span>
|
||||
|
|
|
@ -12,4 +12,59 @@ defmodule LivebookWeb.HelpersTest do
|
|||
Helpers.ansi_to_html_lines("\e[34msmiley\ncat\e[0m")
|
||||
end
|
||||
end
|
||||
|
||||
describe "names_to_html_ids/1" do
|
||||
test "title case" do
|
||||
assert(Helpers.names_to_html_ids(["Title of a Section"]) == ["title-of-a-section"])
|
||||
end
|
||||
|
||||
# Contains a couple of unicode spaces to ensure that we handle those
|
||||
test "space characters" do
|
||||
assert Helpers.names_to_html_ids([" slug \n with spaces \t "]) == ["slug-with-spaces"]
|
||||
end
|
||||
|
||||
test "emoji at end" do
|
||||
assert Helpers.names_to_html_ids(["Test 🦦 "]) == ["test-🦦"]
|
||||
end
|
||||
|
||||
test "emoji in middle" do
|
||||
assert Helpers.names_to_html_ids(["One 🥮 Two"]) == ["one-🥮-two"]
|
||||
end
|
||||
|
||||
test "returns empty list for an empty list" do
|
||||
assert Helpers.names_to_html_ids([]) == []
|
||||
end
|
||||
|
||||
test "returns id-ified strings for different kinds of names" do
|
||||
names = [
|
||||
"Title of a Section",
|
||||
" something with \n many space characters \t "
|
||||
]
|
||||
|
||||
assert Helpers.names_to_html_ids(names) == [
|
||||
"title-of-a-section",
|
||||
"something-with-many-space-characters"
|
||||
]
|
||||
end
|
||||
|
||||
test "enumerates ids when they would be the same" do
|
||||
names = [
|
||||
"Title of a Section",
|
||||
"Some other title",
|
||||
" Title of a Section",
|
||||
"random",
|
||||
" Title of a section",
|
||||
"Title of a Section "
|
||||
]
|
||||
|
||||
assert Helpers.names_to_html_ids(names) == [
|
||||
"title-of-a-section",
|
||||
"some-other-title",
|
||||
"title-of-a-section-2",
|
||||
"random",
|
||||
"title-of-a-section-3",
|
||||
"title-of-a-section-4"
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue