Redesign sidebar (#1325)

Co-authored-by: José Valim <jose.valim@dashbit.co>
Co-authored-by: Jonatan Kłosko <jonatanklosko@gmail.com>
This commit is contained in:
Paulo Valim 2022-08-03 15:50:27 +02:00 committed by GitHub
parent e0db5c24b0
commit 43f5c383e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 186 additions and 155 deletions

View file

@ -4,6 +4,7 @@ import "katex/dist/katex.min.css";
import "@fontsource/inter";
import "@fontsource/inter/500.css";
import "@fontsource/inter/600.css";
import "@fontsource/red-hat-text";
import "@fontsource/jetbrains-mono";
import "phoenix_html";

View file

@ -7,6 +7,7 @@
"dependencies": {
"@fontsource/inter": "^4.2.2",
"@fontsource/jetbrains-mono": "^4.2.2",
"@fontsource/red-hat-text": "^4.2.2",
"assert": "^2.0.0",
"crypto-js": "^4.0.0",
"css-minimizer-webpack-plugin": "^4.0.0",
@ -1680,6 +1681,11 @@
"resolved": "https://registry.npmjs.org/@fontsource/jetbrains-mono/-/jetbrains-mono-4.5.9.tgz",
"integrity": "sha512-qgzRg1dYIPyAOTp1XR6RkDOlNt4o6LVAe9PXR68hQzbwd1xf0S86TWEzNFSL82do8weF/G2ubo4TGxrNKo9D1A=="
},
"node_modules/@fontsource/red-hat-text": {
"version": "4.5.9",
"resolved": "https://registry.npmjs.org/@fontsource/red-hat-text/-/red-hat-text-4.5.9.tgz",
"integrity": "sha512-7jBq3vSTtZt1kJpwRt04EFfAGepY2E9eq7p09zyD4Ibx0rItBy/uoF/6Wmx/1heJurbUxxcBHY/6dKNxBRpb4g=="
},
"node_modules/@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@ -12844,6 +12850,11 @@
"resolved": "https://registry.npmjs.org/@fontsource/jetbrains-mono/-/jetbrains-mono-4.5.9.tgz",
"integrity": "sha512-qgzRg1dYIPyAOTp1XR6RkDOlNt4o6LVAe9PXR68hQzbwd1xf0S86TWEzNFSL82do8weF/G2ubo4TGxrNKo9D1A=="
},
"@fontsource/red-hat-text": {
"version": "4.5.9",
"resolved": "https://registry.npmjs.org/@fontsource/red-hat-text/-/red-hat-text-4.5.9.tgz",
"integrity": "sha512-7jBq3vSTtZt1kJpwRt04EFfAGepY2E9eq7p09zyD4Ibx0rItBy/uoF/6Wmx/1heJurbUxxcBHY/6dKNxBRpb4g=="
},
"@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",

View file

@ -11,6 +11,7 @@
"dependencies": {
"@fontsource/inter": "^4.2.2",
"@fontsource/jetbrains-mono": "^4.2.2",
"@fontsource/red-hat-text": "^4.2.2",
"assert": "^2.0.0",
"crypto-js": "^4.0.0",
"css-minimizer-webpack-plugin": "^4.0.0",

View file

@ -10,6 +10,7 @@ module.exports = {
fontFamily: {
sans: ["Inter"],
mono: ["JetBrains Mono", "monospace"],
logo: ["Red Hat Text"],
},
extend: {
colors: {
@ -73,7 +74,7 @@ module.exports = {
800: "#B7641F",
900: "#934814",
},
'green-bright': {
"green-bright": {
50: "#F0FDF4",
100: "#DCFCE7",
200: "#BBF7D0",
@ -85,7 +86,7 @@ module.exports = {
800: "#166534",
900: "#14532D",
},
'yellow-bright': {
"yellow-bright": {
50: "#FEFCE8",
100: "#FEF9C3",
200: "#FEF08A",

View file

@ -13,7 +13,7 @@ defmodule LivebookWeb.ExploreLive do
{:ok,
socket
|> SidebarHelpers.shared_home_handlers()
|> SidebarHelpers.sidebar_handlers()
|> assign(
lead_notebook_info: lead_notebook_info,
notebook_infos: notebook_infos,
@ -25,14 +25,15 @@ defmodule LivebookWeb.ExploreLive do
def render(assigns) do
~H"""
<div class="flex grow h-full">
<SidebarHelpers.sidebar>
<SidebarHelpers.logo_item socket={@socket} />
<SidebarHelpers.shared_home_footer socket={@socket} current_user={@current_user} />
</SidebarHelpers.sidebar>
<SidebarHelpers.sidebar
socket={@socket}
current_page={Routes.explore_path(@socket, :page)}
current_user={@current_user}
/>
<div class="grow px-6 py-8 overflow-y-auto">
<div class="max-w-screen-md w-full mx-auto px-4 pb-8 space-y-8">
<div>
<PageHelpers.title text="Explore" socket={@socket} />
<PageHelpers.title text="Explore" />
<p class="mt-4 text-gray-700">
Check out a number of examples showcasing various parts of the Elixir ecosystem.
Click on any notebook you like and start playing around with it!

View file

@ -4,7 +4,7 @@ defmodule LivebookWeb.HomeLive do
import LivebookWeb.SessionHelpers
import LivebookWeb.UserHelpers
alias LivebookWeb.{SidebarHelpers, ExploreHelpers}
alias LivebookWeb.{ExploreHelpers, PageHelpers, SidebarHelpers}
alias Livebook.{Sessions, Session, LiveMarkdown, Notebook, FileSystem}
@impl true
@ -19,7 +19,7 @@ defmodule LivebookWeb.HomeLive do
{:ok,
socket
|> SidebarHelpers.shared_home_handlers()
|> SidebarHelpers.sidebar_handlers()
|> assign(
self_path: Routes.home_path(socket, :page),
file: determine_file(params),
@ -39,20 +39,19 @@ defmodule LivebookWeb.HomeLive do
~H"""
<div class="flex grow h-full">
<.live_region role="alert" />
<SidebarHelpers.sidebar>
<SidebarHelpers.shared_home_footer socket={@socket} current_user={@current_user} />
</SidebarHelpers.sidebar>
<SidebarHelpers.sidebar
socket={@socket}
current_page={Routes.home_path(@socket, :page)}
current_user={@current_user}
/>
<div class="grow overflow-y-auto">
<.update_notification version={@new_version} instructions_url={@update_instructions_url} />
<.memory_notification memory={@memory} app_service_url={@app_service_url} />
<div class="max-w-screen-lg w-full mx-auto px-8 pt-8 pb-32 space-y-4">
<div class="flex flex-col space-y-2 items-center pb-4 border-b border-gray-200
<div class="flex flex-col space-y-2 items-center pb-4
sm:flex-row sm:space-y-0 sm:justify-between">
<div class="text-2xl text-gray-800 font-semibold">
<img src="/images/logo-with-text.png" class="h-[50px]" alt="Livebook" />
<h1 class="sr-only">Livebook</h1>
</div>
<div class="flex space-x-2 pt-2" role="navigation" aria-label="new notebook">
<PageHelpers.title text="Home" />
<div class="flex space-x-2" role="navigation" aria-label="new notebook">
<%= live_patch("Import",
to: Routes.home_path(@socket, :import, "url"),
class: "button-base button-outlined-gray whitespace-nowrap"

View file

@ -1,10 +1,6 @@
defmodule LivebookWeb.PageHelpers do
use Phoenix.Component
import LivebookWeb.LiveHelpers
alias LivebookWeb.Router.Helpers, as: Routes
@doc """
Renders page title.
@ -14,15 +10,9 @@ defmodule LivebookWeb.PageHelpers do
"""
def title(assigns) do
~H"""
<div class="relative">
<%= live_redirect to: Routes.home_path(@socket, :page),
class: "hidden md:block absolute top-[50%] left-[-12px] transform -translate-y-1/2 -translate-x-full" do %>
<.remix_icon icon="arrow-left-line" class="text-2xl align-middle" />
<% end %>
<h1 class="text-3xl text-gray-800 font-semibold">
<%= @text %>
</h1>
</div>
<h1 class="text-3xl text-gray-800 font-semibold">
<%= @text %>
</h1>
"""
end
end

View file

@ -5,7 +5,6 @@ defmodule LivebookWeb.SessionLive do
import LivebookWeb.SessionHelpers
import Livebook.Utils, only: [format_bytes: 1]
alias LivebookWeb.SidebarHelpers
alias Livebook.{Sessions, Session, Delta, Notebook, Runtime, LiveMarkdown}
alias Livebook.Notebook.Cell
alias Livebook.JSInterop
@ -96,40 +95,64 @@ defmodule LivebookWeb.SessionLive do
data-global-status={elem(@data_view.global_status, 0)}
data-autofocus-cell-id={@autofocus_cell_id}
>
<SidebarHelpers.sidebar>
<SidebarHelpers.logo_item socket={@socket} />
<SidebarHelpers.button_item
<nav
class="w-16 flex flex-col items-center px-3 py-1 space-y-2 sm:space-y-4 sm:py-7 bg-gray-900"
aria-label="sidebar"
data-el-sidebar
>
<span>
<%= live_redirect to: Routes.home_path(@socket, :page), aria_label: "go to homepage" do %>
<img src="/images/logo.png" height="40" width="40" alt="" />
<% end %>
</span>
<.button_item
icon="booklet-fill"
label="Sections (ss)"
button_attrs={[data_el_sections_list_toggle: true]}
/>
<SidebarHelpers.button_item
<.button_item
icon="group-fill"
label="Connected users (su)"
button_attrs={[data_el_clients_list_toggle: true]}
/>
<SidebarHelpers.button_item
<.button_item
icon="cpu-line"
label="Runtime settings (sr)"
button_attrs={[data_el_runtime_info_toggle: true]}
/>
<SidebarHelpers.link_item
<.link_item
icon="delete-bin-6-fill"
label="Bin (sb)"
path={Routes.session_path(@socket, :bin, @session.id)}
active={@live_action == :bin}
link_attrs={[data_btn_show_bin: true]}
/>
<SidebarHelpers.break_item />
<SidebarHelpers.link_item
<div class="grow"></div>
<.link_item
icon="keyboard-box-fill"
label="Keyboard shortcuts (?)"
path={Routes.session_path(@socket, :shortcuts, @session.id)}
active={@live_action == :shortcuts}
link_attrs={[data_btn_show_shortcuts: true]}
/>
<SidebarHelpers.user_item current_user={@current_user} />
</SidebarHelpers.sidebar>
<span class="tooltip right distant" data-tooltip="User profile">
<button
class="text-gray-400 rounded-xl h-8 w-8 flex items-center justify-center mt-2 group"
aria_label="user profile"
phx-click={show_current_user_modal()}
>
<.user_avatar
user={@current_user}
class="w-8 h-8 group-hover:ring-white group-hover:ring-2"
text_class="text-xs"
/>
</button>
</span>
</nav>
<div
class="flex flex-col h-full w-full max-w-xs absolute z-30 top-0 left-[64px] overflow-y-auto shadow-xl md:static md:shadow-none bg-gray-50 border-r border-gray-100 px-6 py-10"
data-el-side-panel
@ -364,6 +387,34 @@ defmodule LivebookWeb.SessionLive do
"""
end
defp button_item(assigns) do
~H"""
<span class="tooltip right distant" data-tooltip={@label}>
<button
class="text-2xl text-gray-400 hover:text-gray-50 focus:text-gray-50 rounded-xl h-10 w-10 flex items-center justify-center"
aria-label={@label}
{@button_attrs}
>
<.remix_icon icon={@icon} />
</button>
</span>
"""
end
defp link_item(assigns) do
assigns = assign_new(assigns, :link_attrs, fn -> [] end)
~H"""
<span class="tooltip right distant" data-tooltip={@label}>
<%= live_patch [to: @path,
class: "text-gray-400 hover:text-gray-50 focus:text-gray-50 rounded-xl h-10 w-10 flex items-center justify-center #{if(@active, do: "text-gray-50 bg-gray-700")}",
aria_label: @label] ++ @link_attrs do %>
<.remix_icon icon={@icon} class="text-2xl" />
<% end %>
</span>
"""
end
defp sections_list(assigns) do
~H"""
<div class="flex flex-col grow">

View file

@ -9,7 +9,7 @@ defmodule LivebookWeb.SettingsLive do
def mount(_params, _session, socket) do
{:ok,
socket
|> SidebarHelpers.shared_home_handlers()
|> SidebarHelpers.sidebar_handlers()
|> assign(
file_systems: Livebook.Settings.file_systems(),
autosave_path_state: %{
@ -25,16 +25,17 @@ defmodule LivebookWeb.SettingsLive do
def render(assigns) do
~H"""
<div class="flex grow h-full">
<SidebarHelpers.sidebar>
<SidebarHelpers.logo_item socket={@socket} />
<SidebarHelpers.shared_home_footer socket={@socket} current_user={@current_user} />
</SidebarHelpers.sidebar>
<SidebarHelpers.sidebar
socket={@socket}
current_page={Routes.settings_path(@socket, :page)}
current_user={@current_user}
/>
<div class="grow px-6 py-8 overflow-y-auto">
<div class="max-w-screen-md w-full mx-auto px-4 pb-8 space-y-20">
<!-- System settings section -->
<div class="flex flex-col space-y-10">
<div>
<PageHelpers.title text="System settings" socket={@socket} />
<PageHelpers.title text="System settings" />
<p class="mt-4 text-gray-700">
Here you can change global Livebook configuration. Keep in mind
that this configuration gets persisted and will be restored on application

View file

@ -9,130 +9,105 @@ defmodule LivebookWeb.SidebarHelpers do
@doc """
Renders sidebar container.
Other functions in this module render sidebar
items of various type.
"""
def sidebar(assigns) do
~H"""
<nav
class="w-16 flex flex-col items-center px-3 py-1 space-y-2 sm:space-y-4 sm:py-7 bg-gray-900"
class="w-[18.75rem] min-w-[14rem] flex flex-col justify-between py-7 bg-gray-900"
aria-label="sidebar"
data-el-sidebar
>
<%= render_slot(@inner_block) %>
<div class="flex flex-col space-y-3">
<div class="group flex items-center mb-5">
<%= live_redirect to: Routes.home_path(@socket, :page), class: "flex items-center border-l-4 border-gray-900" do %>
<img src="/images/logo.png" class="group mx-2" height="40" width="40" alt="logo livebook" />
<span class="text-gray-300 text-2xl font-logo ml-[-1px] group-hover:text-white pt-1">
Livebook
</span>
<% end %>
<span class="text-gray-300 text-xs font-normal font-sans mx-2.5 pt-3 cursor-default">
v<%= Application.spec(:livebook, :vsn) %>
</span>
</div>
<.sidebar_link
title="Home"
icon="home-6-line"
to={Routes.home_path(@socket, :page)}
current={@current_page}
/>
<.sidebar_link
title="Explore"
icon="compass-3-line"
to={Routes.explore_path(@socket, :page)}
current={@current_page}
/>
<.sidebar_link
title="Settings"
icon="settings-3-line"
to={Routes.settings_path(@socket, :page)}
current={@current_page}
/>
</div>
<div class="flex flex-col">
<%= if Livebook.Config.shutdown_enabled?() do %>
<button
class="h-7 flex items-center text-gray-400 hover:text-white border-l-4 border-transparent hover:border-white"
aria-label="shutdown"
phx-click={
with_confirm(
JS.push("shutdown"),
title: "Shut Down",
description: "Are you sure you want to shut down Livebook now?",
confirm_text: "Shut Down",
confirm_icon: "shut-down-line"
)
}
>
<.remix_icon icon="shut-down-line" class="text-lg leading-6 w-[60px] flex justify-center" />
<span class="text-sm font-medium">
Shut Down
</span>
</button>
<% end %>
<button
class="mt-8 flex items-center group"
aria_label="user profile"
phx-click={show_current_user_modal()}
>
<div class="w-[60px] border-l-4 border-transparent flex justify-center group">
<.user_avatar
user={@current_user}
class="w-8 h-8 group-hover:ring-white group-hover:ring-2"
text_class="text-xs"
/>
</div>
<span class="text-sm text-gray-400 font-medium group-hover:text-white">
<%= @current_user.name %>
</span>
</button>
</div>
</nav>
"""
end
def logo_item(assigns) do
defp sidebar_link(assigns) do
~H"""
<span>
<%= live_redirect to: Routes.home_path(@socket, :page), aria_label: "go to homepage" do %>
<img src="/images/logo.png" height="40" width="40" alt="" />
<% end %>
</span>
"""
end
def button_item(assigns) do
~H"""
<span class="tooltip right distant" data-tooltip={@label}>
<button
class="text-2xl text-gray-400 hover:text-gray-50 focus:text-gray-50 rounded-xl h-10 w-10 flex items-center justify-center"
aria-label={@label}
{@button_attrs}
>
<.remix_icon icon={@icon} />
</button>
</span>
"""
end
def link_item(assigns) do
assigns = assign_new(assigns, :link_attrs, fn -> [] end)
~H"""
<span class="tooltip right distant" data-tooltip={@label}>
<%= live_patch [to: @path,
class: "text-gray-400 hover:text-gray-50 focus:text-gray-50 rounded-xl h-10 w-10 flex items-center justify-center #{if(@active, do: "text-gray-50 bg-gray-700")}",
aria_label: @label] ++ @link_attrs do %>
<.remix_icon icon={@icon} class="text-2xl" />
<% end %>
</span>
"""
end
def shutdown_item(assigns) do
if Livebook.Config.shutdown_enabled?() do
~H"""
<span class="tooltip right distant" data-tooltip="Shutdown">
<button
class="text-2xl text-gray-400 hover:text-gray-50 focus:text-gray-50 rounded-xl h-10 w-10 flex items-center justify-center"
aria-label="shutdown"
phx-click={
with_confirm(
JS.push("shutdown"),
title: "Shutdown",
description: "Are you sure you want to shutdown Livebook?",
confirm_text: "Shutdown",
confirm_icon: "shut-down-line"
)
}
>
<.remix_icon icon="shut-down-line" />
</button>
<%= live_redirect to: @to, class: "h-7 flex items-center hover:text-white #{sidebar_link_text_color(@to, @current)} border-l-4 #{sidebar_link_border_color(@to, @current)} hover:border-white" do %>
<.remix_icon icon={@icon} class="text-lg leading-6 w-[60px] flex justify-center" />
<span class="text-sm font-medium">
<%= @title %>
</span>
"""
else
~H"""
"""
end
end
def break_item(assigns) do
~H"""
<div class="grow"></div>
<% end %>
"""
end
def user_item(assigns) do
~H"""
<span class="tooltip right distant" data-tooltip="User profile">
<button
class="text-gray-400 rounded-xl h-8 w-8 flex items-center justify-center mt-2"
aria_label="user profile"
phx-click={show_current_user_modal()}
>
<.user_avatar user={@current_user} text_class="text-xs" />
</button>
</span>
"""
end
defp sidebar_link_text_color(to, current) when to == current, do: "text-white"
defp sidebar_link_text_color(_to, _current), do: "text-gray-400"
## Shared home functionality
defp sidebar_link_border_color(to, current) when to == current, do: "border-white"
defp sidebar_link_border_color(_to, _current), do: "border-transparent"
@doc """
A footer shared across home, settings, explore, etc.
Note you must call `shared_home_handlers` on mount/3.
"""
def shared_home_footer(assigns) do
~H"""
<.break_item />
<.shutdown_item />
<.link_item
icon="settings-3-fill"
label="Settings"
path={Routes.settings_path(@socket, :page)}
active={false}
/>
<.user_item current_user={@current_user} />
"""
end
def shared_home_handlers(socket) do
def sidebar_handlers(socket) do
if Livebook.Config.shutdown_enabled?() do
attach_hook(socket, :shutdown, :handle_event, fn
"shutdown", _params, socket ->