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";
import "@fontsource/inter/500.css"; import "@fontsource/inter/500.css";
import "@fontsource/inter/600.css"; import "@fontsource/inter/600.css";
import "@fontsource/red-hat-text";
import "@fontsource/jetbrains-mono"; import "@fontsource/jetbrains-mono";
import "phoenix_html"; import "phoenix_html";

View file

@ -7,6 +7,7 @@
"dependencies": { "dependencies": {
"@fontsource/inter": "^4.2.2", "@fontsource/inter": "^4.2.2",
"@fontsource/jetbrains-mono": "^4.2.2", "@fontsource/jetbrains-mono": "^4.2.2",
"@fontsource/red-hat-text": "^4.2.2",
"assert": "^2.0.0", "assert": "^2.0.0",
"crypto-js": "^4.0.0", "crypto-js": "^4.0.0",
"css-minimizer-webpack-plugin": "^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", "resolved": "https://registry.npmjs.org/@fontsource/jetbrains-mono/-/jetbrains-mono-4.5.9.tgz",
"integrity": "sha512-qgzRg1dYIPyAOTp1XR6RkDOlNt4o6LVAe9PXR68hQzbwd1xf0S86TWEzNFSL82do8weF/G2ubo4TGxrNKo9D1A==" "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": { "node_modules/@istanbuljs/load-nyc-config": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "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", "resolved": "https://registry.npmjs.org/@fontsource/jetbrains-mono/-/jetbrains-mono-4.5.9.tgz",
"integrity": "sha512-qgzRg1dYIPyAOTp1XR6RkDOlNt4o6LVAe9PXR68hQzbwd1xf0S86TWEzNFSL82do8weF/G2ubo4TGxrNKo9D1A==" "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": { "@istanbuljs/load-nyc-config": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",

View file

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

View file

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

View file

@ -13,7 +13,7 @@ defmodule LivebookWeb.ExploreLive do
{:ok, {:ok,
socket socket
|> SidebarHelpers.shared_home_handlers() |> SidebarHelpers.sidebar_handlers()
|> assign( |> assign(
lead_notebook_info: lead_notebook_info, lead_notebook_info: lead_notebook_info,
notebook_infos: notebook_infos, notebook_infos: notebook_infos,
@ -25,14 +25,15 @@ defmodule LivebookWeb.ExploreLive do
def render(assigns) do def render(assigns) do
~H""" ~H"""
<div class="flex grow h-full"> <div class="flex grow h-full">
<SidebarHelpers.sidebar> <SidebarHelpers.sidebar
<SidebarHelpers.logo_item socket={@socket} /> socket={@socket}
<SidebarHelpers.shared_home_footer socket={@socket} current_user={@current_user} /> current_page={Routes.explore_path(@socket, :page)}
</SidebarHelpers.sidebar> current_user={@current_user}
/>
<div class="grow px-6 py-8 overflow-y-auto"> <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 class="max-w-screen-md w-full mx-auto px-4 pb-8 space-y-8">
<div> <div>
<PageHelpers.title text="Explore" socket={@socket} /> <PageHelpers.title text="Explore" />
<p class="mt-4 text-gray-700"> <p class="mt-4 text-gray-700">
Check out a number of examples showcasing various parts of the Elixir ecosystem. 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! 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.SessionHelpers
import LivebookWeb.UserHelpers import LivebookWeb.UserHelpers
alias LivebookWeb.{SidebarHelpers, ExploreHelpers} alias LivebookWeb.{ExploreHelpers, PageHelpers, SidebarHelpers}
alias Livebook.{Sessions, Session, LiveMarkdown, Notebook, FileSystem} alias Livebook.{Sessions, Session, LiveMarkdown, Notebook, FileSystem}
@impl true @impl true
@ -19,7 +19,7 @@ defmodule LivebookWeb.HomeLive do
{:ok, {:ok,
socket socket
|> SidebarHelpers.shared_home_handlers() |> SidebarHelpers.sidebar_handlers()
|> assign( |> assign(
self_path: Routes.home_path(socket, :page), self_path: Routes.home_path(socket, :page),
file: determine_file(params), file: determine_file(params),
@ -39,20 +39,19 @@ defmodule LivebookWeb.HomeLive do
~H""" ~H"""
<div class="flex grow h-full"> <div class="flex grow h-full">
<.live_region role="alert" /> <.live_region role="alert" />
<SidebarHelpers.sidebar> <SidebarHelpers.sidebar
<SidebarHelpers.shared_home_footer socket={@socket} current_user={@current_user} /> socket={@socket}
</SidebarHelpers.sidebar> current_page={Routes.home_path(@socket, :page)}
current_user={@current_user}
/>
<div class="grow overflow-y-auto"> <div class="grow overflow-y-auto">
<.update_notification version={@new_version} instructions_url={@update_instructions_url} /> <.update_notification version={@new_version} instructions_url={@update_instructions_url} />
<.memory_notification memory={@memory} app_service_url={@app_service_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="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"> sm:flex-row sm:space-y-0 sm:justify-between">
<div class="text-2xl text-gray-800 font-semibold"> <PageHelpers.title text="Home" />
<img src="/images/logo-with-text.png" class="h-[50px]" alt="Livebook" /> <div class="flex space-x-2" role="navigation" aria-label="new notebook">
<h1 class="sr-only">Livebook</h1>
</div>
<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"

View file

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

View file

@ -5,7 +5,6 @@ defmodule LivebookWeb.SessionLive do
import LivebookWeb.SessionHelpers import LivebookWeb.SessionHelpers
import Livebook.Utils, only: [format_bytes: 1] import Livebook.Utils, only: [format_bytes: 1]
alias LivebookWeb.SidebarHelpers
alias Livebook.{Sessions, Session, Delta, Notebook, Runtime, LiveMarkdown} alias Livebook.{Sessions, Session, Delta, Notebook, Runtime, LiveMarkdown}
alias Livebook.Notebook.Cell alias Livebook.Notebook.Cell
alias Livebook.JSInterop alias Livebook.JSInterop
@ -96,40 +95,64 @@ defmodule LivebookWeb.SessionLive do
data-global-status={elem(@data_view.global_status, 0)} data-global-status={elem(@data_view.global_status, 0)}
data-autofocus-cell-id={@autofocus_cell_id} data-autofocus-cell-id={@autofocus_cell_id}
> >
<SidebarHelpers.sidebar> <nav
<SidebarHelpers.logo_item socket={@socket} /> 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"
<SidebarHelpers.button_item 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" icon="booklet-fill"
label="Sections (ss)" label="Sections (ss)"
button_attrs={[data_el_sections_list_toggle: true]} button_attrs={[data_el_sections_list_toggle: true]}
/> />
<SidebarHelpers.button_item <.button_item
icon="group-fill" icon="group-fill"
label="Connected users (su)" label="Connected users (su)"
button_attrs={[data_el_clients_list_toggle: true]} button_attrs={[data_el_clients_list_toggle: true]}
/> />
<SidebarHelpers.button_item <.button_item
icon="cpu-line" icon="cpu-line"
label="Runtime settings (sr)" label="Runtime settings (sr)"
button_attrs={[data_el_runtime_info_toggle: true]} button_attrs={[data_el_runtime_info_toggle: true]}
/> />
<SidebarHelpers.link_item <.link_item
icon="delete-bin-6-fill" icon="delete-bin-6-fill"
label="Bin (sb)" label="Bin (sb)"
path={Routes.session_path(@socket, :bin, @session.id)} path={Routes.session_path(@socket, :bin, @session.id)}
active={@live_action == :bin} active={@live_action == :bin}
link_attrs={[data_btn_show_bin: true]} link_attrs={[data_btn_show_bin: true]}
/> />
<SidebarHelpers.break_item />
<SidebarHelpers.link_item <div class="grow"></div>
<.link_item
icon="keyboard-box-fill" icon="keyboard-box-fill"
label="Keyboard shortcuts (?)" label="Keyboard shortcuts (?)"
path={Routes.session_path(@socket, :shortcuts, @session.id)} path={Routes.session_path(@socket, :shortcuts, @session.id)}
active={@live_action == :shortcuts} active={@live_action == :shortcuts}
link_attrs={[data_btn_show_shortcuts: true]} 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 <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" 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 data-el-side-panel
@ -364,6 +387,34 @@ defmodule LivebookWeb.SessionLive do
""" """
end 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 defp sections_list(assigns) do
~H""" ~H"""
<div class="flex flex-col grow"> <div class="flex flex-col grow">

View file

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

View file

@ -9,130 +9,105 @@ defmodule LivebookWeb.SidebarHelpers do
@doc """ @doc """
Renders sidebar container. Renders sidebar container.
Other functions in this module render sidebar
items of various type.
""" """
def sidebar(assigns) do def sidebar(assigns) do
~H""" ~H"""
<nav <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" aria-label="sidebar"
data-el-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> </nav>
""" """
end end
def logo_item(assigns) do defp sidebar_link(assigns) do
~H""" ~H"""
<span> <%= 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 %>
<%= live_redirect to: Routes.home_path(@socket, :page), aria_label: "go to homepage" do %> <.remix_icon icon={@icon} class="text-lg leading-6 w-[60px] flex justify-center" />
<img src="/images/logo.png" height="40" width="40" alt="" /> <span class="text-sm font-medium">
<% end %> <%= @title %>
</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>
</span> </span>
""" <% end %>
else
~H"""
"""
end
end
def break_item(assigns) do
~H"""
<div class="grow"></div>
""" """
end end
def user_item(assigns) do defp sidebar_link_text_color(to, current) when to == current, do: "text-white"
~H""" defp sidebar_link_text_color(_to, _current), do: "text-gray-400"
<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
## 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 """ def sidebar_handlers(socket) do
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
if Livebook.Config.shutdown_enabled?() do if Livebook.Config.shutdown_enabled?() do
attach_hook(socket, :shutdown, :handle_event, fn attach_hook(socket, :shutdown, :handle_event, fn
"shutdown", _params, socket -> "shutdown", _params, socket ->