mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-11-09 13:44:53 +08:00
Accessibility improvements - home page (#979)
* Accessibility improvements on home page * Unique ids for file info path buttons * Improves navigation for screen readers in the session list * Landmarks navigation for screen readers * Headings navigation for screen readers * Group navigation - running sessions list * Fix typo * Minor adjustments based on review suggestions
This commit is contained in:
parent
1a0b9e0f7d
commit
904a21a761
8 changed files with 27 additions and 15 deletions
|
|
@ -11,7 +11,7 @@ defmodule LivebookWeb.ExploreHelpers do
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<%= live_redirect to: Routes.explore_path(@socket, :notebook, @notebook_info.slug),
|
<%= live_redirect to: Routes.explore_path(@socket, :notebook, @notebook_info.slug),
|
||||||
class: "flex items-center justify-center p-6 border-2 border-gray-100 rounded-t-2xl h-[150px]" do %>
|
class: "flex items-center justify-center p-6 border-2 border-gray-100 rounded-t-2xl h-[150px]" do %>
|
||||||
<img src={@notebook_info.details.cover_url} class="max-h-full max-w-[75%]" />
|
<img src={@notebook_info.details.cover_url} class="max-h-full max-w-[75%]" alt={"#{@notebook_info.title} logo"} />
|
||||||
<% end %>
|
<% end %>
|
||||||
<div class="px-6 py-4 bg-gray-100 rounded-b-2xl grow">
|
<div class="px-6 py-4 bg-gray-100 rounded-b-2xl grow">
|
||||||
<%= live_redirect @notebook_info.title,
|
<%= live_redirect @notebook_info.title,
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ defmodule LivebookWeb.FileSelectComponent do
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div class="h-full flex flex-col">
|
<div class="h-full flex flex-col">
|
||||||
|
<h2 class="sr-only">File system</h2>
|
||||||
<div class="flex space-x-3 items-center mb-4">
|
<div class="flex space-x-3 items-center mb-4">
|
||||||
<div class="grow flex space-x-1">
|
<div class="grow flex space-x-1">
|
||||||
<.file_system_menu_button
|
<.file_system_menu_button
|
||||||
|
|
@ -77,6 +78,7 @@ defmodule LivebookWeb.FileSelectComponent do
|
||||||
phx-target={@myself}>
|
phx-target={@myself}>
|
||||||
<input class="input"
|
<input class="input"
|
||||||
id="input-path"
|
id="input-path"
|
||||||
|
aria-label="file path"
|
||||||
phx-hook="FocusOnUpdate"
|
phx-hook="FocusOnUpdate"
|
||||||
type="text"
|
type="text"
|
||||||
name="path"
|
name="path"
|
||||||
|
|
@ -145,6 +147,7 @@ defmodule LivebookWeb.FileSelectComponent do
|
||||||
phx-target={@myself}>
|
phx-target={@myself}>
|
||||||
<input
|
<input
|
||||||
id="new_dir_input"
|
id="new_dir_input"
|
||||||
|
aria-label="new directory"
|
||||||
type="text"
|
type="text"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
|
|
@ -267,6 +270,7 @@ defmodule LivebookWeb.FileSelectComponent do
|
||||||
<:toggle>
|
<:toggle>
|
||||||
<button class="w-full flex space-x-2 items-center p-2 rounded-lg hover:bg-gray-100 focus:ring-1 focus:ring-gray-400"
|
<button class="w-full flex space-x-2 items-center p-2 rounded-lg hover:bg-gray-100 focus:ring-1 focus:ring-gray-400"
|
||||||
data-toggle
|
data-toggle
|
||||||
|
aria-label={"#{if @file_info.name == "..", do: "parent directory", else: @file_info.name}"}
|
||||||
phx-click="set_path"
|
phx-click="set_path"
|
||||||
phx-value-path={@file_info.file.path}
|
phx-value-path={@file_info.file.path}
|
||||||
phx-target={@myself}>
|
phx-target={@myself}>
|
||||||
|
|
@ -292,6 +296,7 @@ defmodule LivebookWeb.FileSelectComponent do
|
||||||
<%= if @file_info.editable do %>
|
<%= if @file_info.editable do %>
|
||||||
<button class="menu-item text-gray-500"
|
<button class="menu-item text-gray-500"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
|
aria-label="rename file"
|
||||||
phx-click="rename_file"
|
phx-click="rename_file"
|
||||||
phx-target={@myself}
|
phx-target={@myself}
|
||||||
phx-value-path={@file_info.file.path}>
|
phx-value-path={@file_info.file.path}>
|
||||||
|
|
@ -300,6 +305,7 @@ defmodule LivebookWeb.FileSelectComponent do
|
||||||
</button>
|
</button>
|
||||||
<button class="menu-item text-red-600"
|
<button class="menu-item text-red-600"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
|
aria-label="delete file"
|
||||||
phx-click="delete_file"
|
phx-click="delete_file"
|
||||||
phx-target={@myself}
|
phx-target={@myself}
|
||||||
phx-value-path={@file_info.file.path}>
|
phx-value-path={@file_info.file.path}>
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,9 @@ defmodule LivebookWeb.HomeLive do
|
||||||
sm:flex-row sm:space-y-0 sm:justify-between">
|
sm:flex-row sm:space-y-0 sm:justify-between">
|
||||||
<div class="text-2xl text-gray-800 font-semibold">
|
<div class="text-2xl text-gray-800 font-semibold">
|
||||||
<img src="/images/logo-with-text.png" class="h-[50px]" alt="Livebook" />
|
<img src="/images/logo-with-text.png" class="h-[50px]" alt="Livebook" />
|
||||||
|
<h1 class="sr-only">Livebook</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex space-x-2 pt-2">
|
<div class="flex space-x-2 pt-2" role="navigation" aria-label="new notebook">
|
||||||
<%= live_patch "Import",
|
<%= live_patch "Import",
|
||||||
to: Routes.home_path(@socket, :import, "url"),
|
to: Routes.home_path(@socket, :import, "url"),
|
||||||
class: "button-base button-outlined-gray whitespace-nowrap" %>
|
class: "button-base button-outlined-gray whitespace-nowrap" %>
|
||||||
|
|
@ -55,7 +56,7 @@ defmodule LivebookWeb.HomeLive do
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="h-80">
|
<div class="h-80" role="region" aria-label="file system">
|
||||||
<.live_component module={LivebookWeb.FileSelectComponent}
|
<.live_component module={LivebookWeb.FileSelectComponent}
|
||||||
id="home-file-select"
|
id="home-file-select"
|
||||||
file={@file}
|
file={@file}
|
||||||
|
|
@ -85,7 +86,7 @@ defmodule LivebookWeb.HomeLive do
|
||||||
</.live_component>
|
</.live_component>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="py-12" data-element="explore-section">
|
<div class="py-12" data-element="explore-section" role="region" aria-label="explore section">
|
||||||
<div class="mb-4 flex justify-between items-center">
|
<div class="mb-4 flex justify-between items-center">
|
||||||
<h2 class="uppercase font-semibold text-gray-500">
|
<h2 class="uppercase font-semibold text-gray-500">
|
||||||
Explore
|
Explore
|
||||||
|
|
@ -104,7 +105,7 @@ defmodule LivebookWeb.HomeLive do
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="py-12">
|
<div class="py-12" role="region" aria-label="running sessions">
|
||||||
<.live_component module={LivebookWeb.HomeLive.SessionListComponent}
|
<.live_component module={LivebookWeb.HomeLive.SessionListComponent}
|
||||||
id="session-list"
|
id="session-list"
|
||||||
sessions={@sessions}/>
|
sessions={@sessions}/>
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,11 @@ defmodule LivebookWeb.HomeLive.ImportContentComponent do
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div class="flex-col space-y-5">
|
<div class="flex-col space-y-5">
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700" id="import-from-content">
|
||||||
Import notebook by directly pasting the <span class="font-semibold">live markdown</span> content.
|
Import notebook by directly pasting the <span class="font-semibold">live markdown</span> content.
|
||||||
</p>
|
</p>
|
||||||
<.form let={f} for={:data}
|
<.form let={f} for={:data}
|
||||||
|
id="import-content"
|
||||||
phx-submit="import"
|
phx-submit="import"
|
||||||
phx-change="validate"
|
phx-change="validate"
|
||||||
phx-target={@myself}
|
phx-target={@myself}
|
||||||
|
|
@ -21,6 +22,7 @@ defmodule LivebookWeb.HomeLive.ImportContentComponent do
|
||||||
<%= textarea f, :content, value: @content, class: "input resize-none",
|
<%= textarea f, :content, value: @content, class: "input resize-none",
|
||||||
placeholder: "Notebook content",
|
placeholder: "Notebook content",
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
|
aria_labelledby: "import-from-content",
|
||||||
spellcheck: "false",
|
spellcheck: "false",
|
||||||
rows: 5 %>
|
rows: 5 %>
|
||||||
<button class="mt-5 button-base button-blue" type="submit" disabled={@content == ""}>
|
<button class="mt-5 button-base button-blue" type="submit" disabled={@content == ""}>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ defmodule LivebookWeb.HomeLive.ImportFileUploadComponent do
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div class="flex-col space-y-5">
|
<div class="flex-col space-y-5">
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700" id="import-from-file">
|
||||||
Drag and drop a <code>.livemd</code> file below to import it.
|
Drag and drop a <code>.livemd</code> file below to import it.
|
||||||
</p>
|
</p>
|
||||||
<form id="upload-file-form"
|
<form id="upload-file-form"
|
||||||
|
|
@ -24,7 +24,7 @@ defmodule LivebookWeb.HomeLive.ImportFileUploadComponent do
|
||||||
phx-hook="DragAndDrop"
|
phx-hook="DragAndDrop"
|
||||||
class="flex flex-col items-start"
|
class="flex flex-col items-start"
|
||||||
>
|
>
|
||||||
<%= live_file_input @uploads.notebook, class: "hidden" %>
|
<%= live_file_input @uploads.notebook, class: "hidden", aria_labelledby: "import-from-file" %>
|
||||||
<div data-dropzone class="flex flex-col justify-center items-center w-full rounded-xl border-2 border-dashed border-gray-400 h-48">
|
<div data-dropzone class="flex flex-col justify-center items-center w-full rounded-xl border-2 border-dashed border-gray-400 h-48">
|
||||||
<%= if @uploads.notebook.entries == [] do %>
|
<%= if @uploads.notebook.entries == [] do %>
|
||||||
<span name="placeholder" class="font-medium text-gray-400">Drop your notebook here</span>
|
<span name="placeholder" class="font-medium text-gray-400">Drop your notebook here</span>
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ defmodule LivebookWeb.HomeLive.ImportUrlComponent do
|
||||||
<%= @error_message %>
|
<%= @error_message %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700" id="import-from-url">
|
||||||
Paste the URL to a .livemd file, to a GitHub file, or to a Gist to import it.
|
Paste the URL to a .livemd file, to a GitHub file, or to a Gist to import it.
|
||||||
</p>
|
</p>
|
||||||
<.form let={f} for={:data}
|
<.form let={f} for={:data}
|
||||||
|
|
@ -37,6 +37,7 @@ defmodule LivebookWeb.HomeLive.ImportUrlComponent do
|
||||||
<%= text_input f, :url, value: @url, class: "input",
|
<%= text_input f, :url, value: @url, class: "input",
|
||||||
placeholder: "Notebook URL",
|
placeholder: "Notebook URL",
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
|
aria_labelledby: "import-from-url",
|
||||||
spellcheck: "false" %>
|
spellcheck: "false" %>
|
||||||
<button class="mt-5 button-base button-blue"
|
<button class="mt-5 button-base button-blue"
|
||||||
type="submit"
|
type="submit"
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ defmodule LivebookWeb.HomeLive.SessionListComponent do
|
||||||
<.menu id="sessions-order-menu">
|
<.menu id="sessions-order-menu">
|
||||||
<:toggle>
|
<:toggle>
|
||||||
<button class="w-28 button-base button-outlined-gray px-4 py-1 flex justify-between items-center"
|
<button class="w-28 button-base button-outlined-gray px-4 py-1 flex justify-between items-center"
|
||||||
type="button">
|
type="button" aria-label={"order by - currently ordered by #{order_by_label(@order_by)}"}>
|
||||||
<span><%= order_by_label(@order_by) %></span>
|
<span><%= order_by_label(@order_by) %></span>
|
||||||
<.remix_icon icon="arrow-down-s-line" class="text-lg leading-none align-middle ml-1" />
|
<.remix_icon icon="arrow-down-s-line" class="text-lg leading-none align-middle ml-1" />
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -101,12 +101,13 @@ defmodule LivebookWeb.HomeLive.SessionListComponent do
|
||||||
|
|
||||||
defp session_list(assigns) do
|
defp session_list(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col" role="group" aria-label="running sessions list">
|
||||||
<%= for session <- @sessions do %>
|
<%= for session <- @sessions do %>
|
||||||
<div class="py-4 flex items-center border-b border-gray-300"
|
<div class="py-4 flex items-center border-b border-gray-300"
|
||||||
data-test-session-id={session.id}>
|
data-test-session-id={session.id}>
|
||||||
<div id={"#{session.id}-checkbox"} phx-update="ignore">
|
<div id={"#{session.id}-checkbox"} phx-update="ignore">
|
||||||
<input type="checkbox" name="session_ids[]" value={session.id}
|
<input type="checkbox" name="session_ids[]" value={session.id}
|
||||||
|
aria-label={session.notebook_name}
|
||||||
class="checkbox-base hidden mr-3"
|
class="checkbox-base hidden mr-3"
|
||||||
data-element="bulk-edit-member"
|
data-element="bulk-edit-member"
|
||||||
phx-click={JS.dispatch("lb:session_list:on_selection_change")}>
|
phx-click={JS.dispatch("lb:session_list:on_selection_change")}>
|
||||||
|
|
@ -187,7 +188,7 @@ defmodule LivebookWeb.HomeLive.SessionListComponent do
|
||||||
assigns = assign(assigns, free: free, used: used, total: total, percentage: percentage)
|
assigns = assign(assigns, free: free, used: used, total: total, percentage: percentage)
|
||||||
|
|
||||||
~H"""
|
~H"""
|
||||||
<div class="pr-4">
|
<div class="pr-4" role="group" aria-label="memory information">
|
||||||
<span class="tooltip top" data-tooltip={"#{format_bytes(@free)} available"}>
|
<span class="tooltip top" data-tooltip={"#{format_bytes(@free)} available"}>
|
||||||
<svg viewbox="-10 5 50 25" width="30" height="30" xmlns="http://www.w3.org/2000/svg">
|
<svg viewbox="-10 5 50 25" width="30" height="30" xmlns="http://www.w3.org/2000/svg">
|
||||||
<circle cx="16.91549431" cy="16.91549431" r="15.91549431"
|
<circle cx="16.91549431" cy="16.91549431" r="15.91549431"
|
||||||
|
|
@ -198,6 +199,7 @@ defmodule LivebookWeb.HomeLive.SessionListComponent do
|
||||||
<div class="hidden md:flex">
|
<div class="hidden md:flex">
|
||||||
<span class="px-2 py-1 text-sm text-gray-500 font-medium">
|
<span class="px-2 py-1 text-sm text-gray-500 font-medium">
|
||||||
<%= format_bytes(@used) %> / <%= format_bytes(@total) %>
|
<%= format_bytes(@used) %> / <%= format_bytes(@total) %>
|
||||||
|
<span class="sr-only"><%= @percentage %> percent used</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -207,11 +209,11 @@ defmodule LivebookWeb.HomeLive.SessionListComponent do
|
||||||
|
|
||||||
defp edit_sessions(assigns) do
|
defp edit_sessions(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div class="mx-4 mr-2 text-gray-600 flex flex-row gap-1">
|
<div class="mx-4 mr-2 text-gray-600 flex flex-row gap-1" role="group" aria-label="bulk actions for sessions">
|
||||||
<.menu id="edit-sessions">
|
<.menu id="edit-sessions">
|
||||||
<:toggle>
|
<:toggle>
|
||||||
<button id="toggle-edit" class="w-28 button-base button-outlined-gray px-4 pl-2 py-1"
|
<button id="toggle-edit" class="w-28 button-base button-outlined-gray px-4 pl-2 py-1"
|
||||||
phx-click={toggle_edit(:on)} type="button">
|
phx-click={toggle_edit(:on)} type="button" aria-label="toggle edit">
|
||||||
<.remix_icon icon="list-check-2" class="text-lg leading-none align-middle ml-1" />
|
<.remix_icon icon="list-check-2" class="text-lg leading-none align-middle ml-1" />
|
||||||
<span>Edit</span>
|
<span>Edit</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ defmodule LivebookWeb.SidebarHelpers do
|
||||||
"""
|
"""
|
||||||
def sidebar(assigns) do
|
def sidebar(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<nav class="w-16 flex flex-col items-center space-y-4 px-3 py-7 bg-gray-900">
|
<nav class="w-16 flex flex-col items-center space-y-4 px-3 py-7 bg-gray-900" aria-label="sidebar">
|
||||||
<%= render_slot(@inner_block) %>
|
<%= render_slot(@inner_block) %>
|
||||||
</nav>
|
</nav>
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue