mirror of
https://github.com/livebook-dev/livebook.git
synced 2024-12-28 02:31:53 +08:00
Improve tab navigation (#109)
* Ignore editor for tab movement * Improve tab behaviour within notebook * Highlight focused regular buttons * Show tooltips on focused elements
This commit is contained in:
parent
2846503da6
commit
af79a0fd2f
9 changed files with 71 additions and 51 deletions
|
@ -5,7 +5,7 @@
|
|||
}
|
||||
|
||||
.button:not(:disabled) {
|
||||
@apply hover:bg-gray-50;
|
||||
@apply hover:bg-gray-50 focus:bg-gray-50;
|
||||
}
|
||||
|
||||
.button:disabled {
|
||||
|
@ -21,7 +21,7 @@
|
|||
}
|
||||
|
||||
.button-danger:not(:disabled) {
|
||||
@apply hover:bg-red-100;
|
||||
@apply hover:bg-red-100 focus:bg-red-100;
|
||||
}
|
||||
|
||||
.button-primary {
|
||||
|
@ -29,7 +29,7 @@
|
|||
}
|
||||
|
||||
.button-primary:not(:disabled) {
|
||||
@apply hover:bg-blue-700;
|
||||
@apply hover:bg-blue-700 focus:bg-blue-700;
|
||||
}
|
||||
|
||||
.choice-button {
|
||||
|
@ -40,6 +40,18 @@
|
|||
@apply bg-blue-100 border-blue-600;
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
@apply p-1 flex items-center justify-center text-gray-400 hover:text-gray-800;
|
||||
}
|
||||
|
||||
.icon-button:focus {
|
||||
@apply rounded-full bg-gray-100;
|
||||
}
|
||||
|
||||
.icon-button i {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
/* Form fields */
|
||||
|
||||
.input {
|
||||
|
@ -88,9 +100,3 @@
|
|||
.tabs .tab.active {
|
||||
@apply text-blue-600 border-blue-600;
|
||||
}
|
||||
|
||||
/* Icons */
|
||||
|
||||
.action-icon {
|
||||
@apply text-gray-400 hover:text-gray-800;
|
||||
}
|
||||
|
|
|
@ -42,13 +42,16 @@ solely client-side operations.
|
|||
@apply border-blue-300 border-opacity-100;
|
||||
}
|
||||
|
||||
[data-element="cell"]:not([data-js-focused]) [data-element="actions"] {
|
||||
@apply invisible;
|
||||
[data-element="cell"]:not([data-js-focused])
|
||||
[data-element="actions"]:not(:focus-within) {
|
||||
/* Note: using opacity, so the buttons are focusable (via tab navigation)
|
||||
and when focused we show the actions back. */
|
||||
@apply opacity-0 pointer-events-none;
|
||||
}
|
||||
|
||||
[data-element="cell"]:not([data-js-focused]):hover
|
||||
[data-element="primary-actions"] {
|
||||
@apply visible;
|
||||
[data-element="actions"][data-primary] {
|
||||
@apply opacity-100 pointer-events-auto;
|
||||
}
|
||||
|
||||
[data-element="section-list-item"][data-js-is-viewed] {
|
||||
|
|
|
@ -11,7 +11,7 @@ Example usage:
|
|||
/* Tooltip element wrapping the actual hoverable element */
|
||||
.tooltip {
|
||||
position: relative;
|
||||
--distance: 0px;
|
||||
--distance: 4px;
|
||||
--arrow-size: 5px;
|
||||
--show-delay: 0.5s;
|
||||
}
|
||||
|
@ -55,12 +55,14 @@ Example usage:
|
|||
transition-delay: 0s;
|
||||
}
|
||||
|
||||
.tooltip:hover:before {
|
||||
.tooltip:hover:before,
|
||||
.tooltip:focus-within:before {
|
||||
visibility: visible;
|
||||
transition-delay: var(--show-delay);
|
||||
}
|
||||
|
||||
.tooltip:hover:after {
|
||||
.tooltip:hover:after,
|
||||
.tooltip:focus-within:after {
|
||||
visibility: visible;
|
||||
transition-delay: var(--show-delay);
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ class LiveEditor {
|
|||
renderLineHighlight: "none",
|
||||
theme: "custom",
|
||||
fontFamily: "JetBrains Mono",
|
||||
tabIndex: -1,
|
||||
});
|
||||
|
||||
this.editor.getModel().updateOptions({
|
||||
|
|
|
@ -16,31 +16,34 @@ defmodule LivebookWeb.CellComponent do
|
|||
|
||||
def render_cell_content(%{cell: %{type: :markdown}} = assigns) do
|
||||
~L"""
|
||||
<div class="mb-1 flex items-center justify-end" data-element="actions">
|
||||
<div class="relative z-10 flex items-center justify-end space-x-2">
|
||||
<div class="mb-1 flex items-center justify-end">
|
||||
<div class="relative z-10 flex items-center justify-end space-x-2" data-element="actions">
|
||||
<span class="tooltip top" aria-label="Edit content">
|
||||
<button data-element="enable-insert-mode-button">
|
||||
<%= remix_icon("pencil-line", class: "text-xl action-icon") %>
|
||||
<button class="icon-button" data-element="enable-insert-mode-button">
|
||||
<%= remix_icon("pencil-line", class: "text-xl") %>
|
||||
</button>
|
||||
</span>
|
||||
<span class="tooltip top" aria-label="Move up">
|
||||
<button phx-click="move_cell"
|
||||
<button class="icon-button"
|
||||
phx-click="move_cell"
|
||||
phx-value-cell_id="<%= @cell.id %>"
|
||||
phx-value-offset="-1">
|
||||
<%= remix_icon("arrow-up-s-line", class: "text-xl action-icon") %>
|
||||
<%= remix_icon("arrow-up-s-line", class: "text-xl") %>
|
||||
</button>
|
||||
</span>
|
||||
<span class="tooltip top" aria-label="Move down">
|
||||
<button phx-click="move_cell"
|
||||
<button class="icon-button"
|
||||
phx-click="move_cell"
|
||||
phx-value-cell_id="<%= @cell.id %>"
|
||||
phx-value-offset="1">
|
||||
<%= remix_icon("arrow-down-s-line", class: "text-xl action-icon") %>
|
||||
<%= remix_icon("arrow-down-s-line", class: "text-xl") %>
|
||||
</button>
|
||||
</span>
|
||||
<span class="tooltip top" aria-label="Delete">
|
||||
<button phx-click="delete_cell"
|
||||
<button class="icon-button"
|
||||
phx-click="delete_cell"
|
||||
phx-value-cell_id="<%= @cell.id %>">
|
||||
<%= remix_icon("delete-bin-6-line", class: "text-xl action-icon") %>
|
||||
<%= remix_icon("delete-bin-6-line", class: "text-xl") %>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -64,10 +67,10 @@ defmodule LivebookWeb.CellComponent do
|
|||
|
||||
def render_cell_content(%{cell: %{type: :elixir}} = assigns) do
|
||||
~L"""
|
||||
<div class="mb-1 flex justify-between" data-element="actions">
|
||||
<div class="relative z-10 flex items-center justify-end space-x-2" data-element="primary-actions">
|
||||
<div class="mb-1 flex justify-between">
|
||||
<div class="relative z-10 flex items-center justify-end space-x-2" data-element="actions" data-primary>
|
||||
<%= if @cell_info.evaluation_status == :ready do %>
|
||||
<button class="text-gray-600 hover:text-gray-800 flex space-x-1 items-center"
|
||||
<button class="text-gray-600 hover:text-gray-800 focus:text-gray-800 flex space-x-1 items-center"
|
||||
phx-click="queue_cell_evaluation"
|
||||
phx-value-cell_id="<%= @cell.id %>">
|
||||
<%= remix_icon("play-circle-fill", class: "text-xl") %>
|
||||
|
@ -76,7 +79,7 @@ defmodule LivebookWeb.CellComponent do
|
|||
</span>
|
||||
</button>
|
||||
<% else %>
|
||||
<button class="text-gray-600 hover:text-gray-800 flex space-x-1 items-center"
|
||||
<button class="text-gray-600 hover:text-gray-800 focus:text-gray-800 flex space-x-1 items-center"
|
||||
phx-click="cancel_cell_evaluation"
|
||||
phx-value-cell_id="<%= @cell.id %>">
|
||||
<%= remix_icon("stop-circle-fill", class: "text-xl") %>
|
||||
|
@ -86,30 +89,33 @@ defmodule LivebookWeb.CellComponent do
|
|||
</button>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="relative z-10 flex items-center justify-end space-x-2">
|
||||
<div class="relative z-10 flex items-center justify-end space-x-2" data-element="actions">
|
||||
<span class="tooltip top" aria-label="Cell settings">
|
||||
<%= live_patch to: Routes.session_path(@socket, :cell_settings, @session_id, @cell.id) do %>
|
||||
<%= remix_icon("list-settings-line", class: "text-xl action-icon") %>
|
||||
<%= live_patch to: Routes.session_path(@socket, :cell_settings, @session_id, @cell.id), class: "icon-button" do %>
|
||||
<%= remix_icon("list-settings-line", class: "text-xl") %>
|
||||
<% end %>
|
||||
</span>
|
||||
<span class="tooltip top" aria-label="Move up">
|
||||
<button phx-click="move_cell"
|
||||
<button class="icon-button"
|
||||
phx-click="move_cell"
|
||||
phx-value-cell_id="<%= @cell.id %>"
|
||||
phx-value-offset="-1">
|
||||
<%= remix_icon("arrow-up-s-line", class: "text-xl action-icon") %>
|
||||
<%= remix_icon("arrow-up-s-line", class: "text-xl") %>
|
||||
</button>
|
||||
</span>
|
||||
<span class="tooltip top" aria-label="Move down">
|
||||
<button phx-click="move_cell"
|
||||
<button class="icon-button"
|
||||
phx-click="move_cell"
|
||||
phx-value-cell_id="<%= @cell.id %>"
|
||||
phx-value-offset="1">
|
||||
<%= remix_icon("arrow-down-s-line", class: "text-xl action-icon") %>
|
||||
<%= remix_icon("arrow-down-s-line", class: "text-xl") %>
|
||||
</button>
|
||||
</span>
|
||||
<span class="tooltip top" aria-label="Delete">
|
||||
<button phx-click="delete_cell"
|
||||
<button class="icon-button"
|
||||
phx-click="delete_cell"
|
||||
phx-value-cell_id="<%= @cell.id %>">
|
||||
<%= remix_icon("delete-bin-6-line", class: "text-xl action-icon") %>
|
||||
<%= remix_icon("delete-bin-6-line", class: "text-xl") %>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -4,15 +4,15 @@ defmodule LivebookWeb.InsertCellComponent do
|
|||
def render(assigns) do
|
||||
~L"""
|
||||
<div class="relative top-0.5 m-0 flex justify-center">
|
||||
<div class="absolute z-10 <%= if(@persistent, do: "opacity-100", else: "opacity-0") %> hover:opacity-100 flex space-x-2 justify-center items-center">
|
||||
<button class="py-1 px-2 text-sm text-gray-600 font-medium rounded-lg border border-gray-200 bg-gray-50 hover:bg-gray-100"
|
||||
<div class="absolute z-10 <%= if(@persistent, do: "opacity-100", else: "opacity-0") %> hover:opacity-100 focus-within:opacity-100 flex space-x-2 justify-center items-center">
|
||||
<button class="py-1 px-2 text-sm text-gray-600 font-medium rounded-lg border border-gray-200 bg-gray-50 hover:bg-gray-100 focus:bg-gray-100"
|
||||
phx-click="insert_cell"
|
||||
phx-value-type="markdown"
|
||||
phx-value-section_id="<%= @section_id %>"
|
||||
phx-value-index="<%= @index %>">
|
||||
+ Markdown
|
||||
</button>
|
||||
<button class="py-1 px-2 text-sm text-gray-600 font-medium rounded-lg border border-gray-200 bg-gray-50 hover:bg-gray-100"
|
||||
<button class="py-1 px-2 text-sm text-gray-600 font-medium rounded-lg border border-gray-200 bg-gray-50 hover:bg-gray-100 focus:bg-gray-100"
|
||||
phx-click="insert_cell"
|
||||
phx-value-type="elixir"
|
||||
phx-value-section_id="<%= @section_id %>"
|
||||
|
|
|
@ -18,8 +18,8 @@ defmodule LivebookWeb.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="Delete">
|
||||
<button phx-click="delete_section" phx-value-section_id="<%= @section.id %>" tabindex="-1">
|
||||
<%= remix_icon("delete-bin-6-line", class: "text-xl action-icon") %>
|
||||
<button class="icon-button" phx-click="delete_section" phx-value-section_id="<%= @section.id %>" tabindex="-1">
|
||||
<%= remix_icon("delete-bin-6-line", class: "text-xl") %>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -79,19 +79,21 @@ defmodule LivebookWeb.SessionLive do
|
|||
</div>
|
||||
<% end %>
|
||||
<span class="tooltip right distant" aria-label="Sections">
|
||||
<button class="text-2xl text-gray-600 hover:text-gray-50" data-element="sections-panel-toggle">
|
||||
<button class="text-2xl text-gray-600 hover:text-gray-50 focus:text-gray-50" data-element="sections-panel-toggle">
|
||||
<%= remix_icon("booklet-fill") %>
|
||||
</button>
|
||||
</span>
|
||||
<span class="tooltip right distant" aria-label="Notebook settings">
|
||||
<%= live_patch to: Routes.session_path(@socket, :settings, @session_id, "file") do %>
|
||||
<%= remix_icon("settings-4-fill", class: "text-2xl text-gray-600 hover:text-gray-50 #{if(@live_action == :settings, do: "text-gray-50")}") %>
|
||||
<%= live_patch to: Routes.session_path(@socket, :settings, @session_id, "file"),
|
||||
class: "text-gray-600 hover:text-gray-50 focus:text-gray-50 #{if(@live_action == :settings, do: "text-gray-50")}" do %>
|
||||
<%= remix_icon("settings-4-fill", class: "text-2xl") %>
|
||||
<% end %>
|
||||
</span>
|
||||
<div class="flex-grow"></div>
|
||||
<span class="tooltip right distant" aria-label="Keyboard shortcuts">
|
||||
<%= live_patch to: Routes.session_path(@socket, :shortcuts, @session_id) do %>
|
||||
<%= remix_icon("keyboard-box-fill", class: "text-2xl text-gray-600 hover:text-gray-50") %>
|
||||
<%= live_patch to: Routes.session_path(@socket, :shortcuts, @session_id),
|
||||
class: "text-gray-600 hover:text-gray-50 focus:text-gray-50" do %>
|
||||
<%= remix_icon("keyboard-box-fill", class: "text-2xl") %>
|
||||
<% end %>
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -17,8 +17,8 @@ defmodule LivebookWeb.SessionsComponent do
|
|||
</div>
|
||||
</div>
|
||||
<div class="relative">
|
||||
<button data-element="menu-toggle">
|
||||
<%= remix_icon("more-2-fill", class: "text-xl action-icon") %>
|
||||
<button class="icon-button" data-element="menu-toggle">
|
||||
<%= remix_icon("more-2-fill", class: "text-xl") %>
|
||||
</button>
|
||||
<div class="absolute right-0 z-20 rounded-lg shadow-center bg-white flex flex-col py-2" data-element="menu">
|
||||
<button class="flex space-x-3 px-5 py-2 items-center text-gray-500 hover:bg-gray-50"
|
||||
|
|
Loading…
Reference in a new issue