Move more styles to components (#1723)

This commit is contained in:
Jonatan Kłosko 2023-02-23 19:07:00 +01:00 committed by GitHub
parent 36e2d2b277
commit e78b3a930c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 336 additions and 414 deletions

View file

@ -46,14 +46,6 @@
@apply text-xl leading-none;
}
.choice-button {
@apply px-5 py-2 rounded-lg border text-gray-700 bg-white border-gray-200;
}
.choice-button.active {
@apply bg-blue-100 border-blue-600;
}
.icon-button {
@apply p-1 flex items-center justify-center text-gray-500 hover:text-gray-900 rounded-full;
}
@ -112,44 +104,7 @@
@apply appearance-none border-transparent bg-blue-600 hover:bg-blue-700 cursor-pointer rounded-xl;
}
.input-select {
@apply w-60;
}
.input-label {
@apply mb-0.5 text-sm text-gray-800 font-medium;
}
.input-error {
@apply mt-2 text-red-600 italic text-xs;
}
.switch-button {
@apply relative inline-block w-14 h-7 select-none;
}
.switch-button--disabled {
@apply pointer-events-none opacity-50;
}
.switch-button__checkbox {
@apply appearance-none absolute block w-7 h-7 rounded-full bg-white border-[5px] border-gray-200 cursor-pointer transition-all duration-300;
}
.switch-button__bg {
@apply block h-full w-full rounded-full bg-gray-200 cursor-pointer transition-all duration-300;
}
.switch-button__checkbox:checked {
@apply bg-white border-blue-600;
transform: translateX(100%);
}
.switch-button__checkbox:checked + .switch-button__bg {
@apply bg-blue-600;
}
.radio-base {
.radio {
appearance: none;
width: 20px;
height: 20px;
@ -160,15 +115,15 @@
background-repeat: no-repeat;
}
.radio-base:checked {
.radio:checked {
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='10' cy='10' r='9.5' stroke='%233E64FF' fill='white' /%3e%3ccircle cx='10' cy='10' r='6' fill='%233E64FF' /%3e%3c/svg%3e");
}
.checkbox-base {
.checkbox {
@apply h-5 w-5 appearance-none border border-gray-300 rounded text-blue-600 cursor-pointer;
}
.checkbox-base:checked {
.checkbox:checked {
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
border-color: transparent;
background-color: currentColor;
@ -207,76 +162,6 @@
@apply text-blue-600 border-blue-600;
}
/* Toggleable menu */
.menu {
@apply relative;
}
.menu__content {
@apply absolute z-[100] rounded-lg bg-white flex flex-col py-2;
box-shadow: 0px 15px 99px rgba(13, 24, 41, 0.15);
}
.menu__content--top-right {
@apply top-0 right-0 transform -translate-y-full -mt-1;
}
.menu__content--top-left {
@apply top-0 left-0 transform -translate-y-full -mt-1;
}
.menu__content--bottom-right {
@apply bottom-0 right-0 transform translate-y-full -mb-1;
}
.menu__content--bottom-left {
@apply bottom-0 left-0 transform translate-y-full -mb-1;
}
.menu__content--top-left.menu__content--distant,
.menu__content--top-right.menu__content--distant {
@apply -mt-2;
}
.menu__content--bottom-left.menu__content--distant,
.menu__content--bottom-right.menu__content--distant {
@apply -mb-2;
}
.menu:not(.menu--open) > .menu__overlay,
.menu:not(.menu--open) > .menu__content {
@apply hidden;
}
.menu.menu--open > .menu__overlay {
@apply fixed z-[90] inset-0;
}
.menu-item {
@apply w-full flex space-x-3 px-5 py-2 items-center hover:bg-gray-100 focus:bg-gray-100 whitespace-nowrap;
}
.menu-item:disabled {
@apply pointer-events-none opacity-50;
}
.menu-item--disabled {
@apply pointer-events-none opacity-50;
}
.submenu {
@apply relative;
}
.submenu:not(:hover):not(:focus-within) .submenu__content {
@apply hidden;
}
.submenu__content {
@apply absolute -top-2 right-0 translate-x-full pl-2;
}
/* Boxes */
.error-box {
@ -286,25 +171,4 @@
.info-box {
@apply p-4 bg-gray-100 text-sm text-gray-500 font-medium rounded-lg;
}
/* Cards */
.card-item {
@apply cursor-pointer;
}
.card-item:not(.selected) .card-item-logo {
@apply border-gray-100;
}
.card-item:not(.selected) .card-item-body {
@apply bg-gray-100;
}
.card-item.selected .card-item-logo {
@apply border-gray-200;
}
.card-item.selected .card-item-body {
@apply bg-gray-200;
}
}

View file

@ -1,15 +1,17 @@
body {
font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica,
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
}
@layer base {
body {
font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto,
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
}
/* Remove the default outline on focused elements */
:focus,
button:focus {
outline: none;
}
/* Remove the default outline on focused elements */
:focus,
button:focus {
outline: none;
}
menu {
margin: 0;
padding: 0;
menu {
margin: 0;
padding: 0;
}
}

View file

@ -34,6 +34,8 @@ const ImageInput = {
this.cameraPreviewEl = this.el.querySelector(`[data-camera-preview]`);
this.cameraListEl = this.el.querySelector(`[data-camera-list]`);
this.cameraItemTemplateEl = this.cameraListEl.firstElementChild;
this.cameraItemTemplateEl.remove();
this.uploadButton = this.el.querySelector(`[data-btn-upload]`);
this.openCameraButton = this.el.querySelector(`[data-btn-open-camera]`);
@ -217,18 +219,17 @@ const ImageInput = {
label: device.label,
}));
this.cameraListEl.innerHTML = [
[
{ deviceId: "system_default", label: "System Default" },
...deviceOptions,
]
.map(
({ deviceId, label }) => `
<button class="menu-item text-gray-500" role="menuitem" data-camera-id="${deviceId}">
<span class="font-medium">${label}</span>
</button>
`
)
.join("");
].forEach(({ deviceId, label }) => {
const item = this.cameraItemTemplateEl.cloneNode(true);
item
.querySelector("[data-camera-id]")
.setAttribute("data-camera-id", deviceId);
item.querySelector("[data-label]").innerHTML = label;
this.cameraListEl.appendChild(item);
});
})
.catch((error) => {
console.error(error);

View file

@ -202,7 +202,7 @@ defmodule LivebookWeb.CoreComponents do
<h3 class="text-2xl font-semibold text-gray-800" data-title></h3>
<p class="mt-8 text-gray-700" data-description></p>
<label class="mt-6 text-gray-700 flex items-center" data-opt-out>
<input class="checkbox-base mr-3" type="checkbox" />
<input class="checkbox mr-3" type="checkbox" />
<span class="text-sm">
Don't show this message again
</span>
@ -304,9 +304,12 @@ defmodule LivebookWeb.CoreComponents do
<:toggle>
<button>Open</button>
</:toggle>
<:content>
<button class"menu-item" role="menuitem">Option 1</button>
</:content>
<.menu_item>
<button role="menuitem">Option 1</button>
</.menu_item>
<.menu_item>
<button role="menuitem">Option 2</button>
</.menu_item>
</.menu>
"""
@ -326,66 +329,113 @@ defmodule LivebookWeb.CoreComponents do
doc: "whether secondary click (usually right mouse click) should open the menu"
slot :toggle, required: true
slot :content, required: true
slot :inner_block, required: true
def menu(assigns) do
~H"""
<div class="menu" id={@id}>
<div class="relative" id={@id}>
<div
phx-click={not @disabled && JS.add_class("menu--open", to: "##{@id}")}
phx-click={not @disabled && show_menu(@id)}
data-contextmenu-trigger-click={@secondary_click}
phx-window-keydown={JS.remove_class("menu--open", to: "##{@id}")}
phx-window-keydown={hide_menu(@id)}
phx-key="escape"
>
<%= render_slot(@toggle) %>
</div>
<div class="menu__overlay" phx-click-away={JS.remove_class("menu--open", to: "##{@id}")}></div>
<div id={"#{@id}-overlay"} class="fixed z-[90] inset-0 hidden" phx-click-away={hide_menu(@id)}>
</div>
<menu
class={["menu__content", menu_content_class(@position), @distant && "menu__content--distant"]}
id={"#{@id}-content"}
class={[
"absolute z-[100] rounded-lg bg-white flex flex-col py-2 shadow-[0_15px_99px_-0px_rgba(12,24,41,0.15)] hidden",
menu_position_class(@position),
@distant && menu_distant_class(@position)
]}
role="menu"
phx-click-away={JS.remove_class("menu--open", to: "##{@id}")}
phx-click-away={hide_menu(@id)}
>
<%= render_slot(@content) %>
<%= render_slot(@inner_block) %>
</menu>
</div>
"""
end
defp menu_content_class(:top_left), do: "menu__content--top-left"
defp menu_content_class(:top_right), do: "menu__content--top-right"
defp menu_content_class(:bottom_left), do: "menu__content--bottom-left"
defp menu_content_class(:bottom_right), do: "menu__content--bottom-right"
defp show_menu(id) do
JS.show(to: "##{id}-overlay")
|> JS.show(to: "##{id}-content", display: "flex")
end
defp hide_menu(id) do
JS.hide(to: "##{id}-overlay")
|> JS.hide(to: "##{id}-content")
end
defp menu_position_class(:top_left), do: "top-0 left-0 transform -translate-y-full -mt-1"
defp menu_position_class(:top_right), do: "top-0 right-0 transform -translate-y-full -mt-1"
defp menu_position_class(:bottom_left), do: "bottom-0 left-0 transform translate-y-full -mb-1"
defp menu_position_class(:bottom_right), do: "bottom-0 right-0 transform translate-y-full -mb-1"
defp menu_distant_class(position) when position in [:top_left, :top_right], do: "-mt-2"
defp menu_distant_class(position) when position in [:bottom_left, :bottom_right], do: "-mb-2"
@doc """
A menu item that shows a submenu on hover.
Wraps a menu item that shows a submenu on hover.
This component should be used within `menu/1` content.
## Example
<.submenu>
<button class"menu-item" role="menuitem">Submenu</button>
<:content>
<:primary>
<button class"menu-item" role="menuitem">Submenu</button>
</:primary>
<.menu_item>
<button class"menu-item" role="menuitem">Option 1</button>
</:content>
</.menu_item>
</.submenu>
"""
slot :primary, required: true
slot :inner_block, required: true
slot :content, required: true
def submenu(assigns) do
~H"""
<div class="submenu">
<%= render_slot(@inner_block) %>
<div class="submenu__content">
<menu class="menu__content relative mt-0">
<%= render_slot(@content) %>
<div class="group relative">
<%= render_slot(@primary) %>
<div class="absolute -top-2 right-0 translate-x-full pl-2 hidden group-hover:flex group-focus-within:flex">
<menu class="relative mt-0 z-[100] rounded-lg bg-white flex flex-col py-2 shadow-[0_15px_99px_-0px_rgba(12,24,41,0.15)]">
<%= render_slot(@inner_block) %>
</menu>
</div>
</div>
"""
end
@doc """
Renders a menu item used in `menu/1` and `submenu/1`.
"""
attr :disabled, :boolean, default: false
attr :variant, :atom, default: :default, values: [:default, :selected, :danger]
slot :inner_block, required: true
def menu_item(assigns) do
~H"""
<li class={[
"[&>:first-child]:w-full [&>:first-child]:flex [&>:first-child]:space-x-3 [&>:first-child]:px-5 [&>:first-child]:py-2 [&>:first-child]:items-center [&>:first-child:hover]:bg-gray-100 [&>:first-child:focus]:bg-gray-100 [&>:first-child]:whitespace-nowrap font-medium",
menu_item_class(@variant),
@disabled && "pointer-events-none opacity-50"
]}>
<%= render_slot(@inner_block) %>
</li>
"""
end
defp menu_item_class(:default), do: "text-gray-500"
defp menu_item_class(:selected), do: "text-gray-900"
defp menu_item_class(:danger), do: "text-red-600"
@doc """
Renders a text content skeleton.
"""
@ -490,7 +540,15 @@ defmodule LivebookWeb.CoreComponents do
|> assign_new(:disabled, fn -> assigns.active end)
~H"""
<button class={["choice-button", @active && "active", @class]} disabled={@disabled} {@rest}>
<button
class={[
"px-5 py-2 rounded-lg border text-gray-700 bg-white border-gray-200",
@active && "bg-blue-100 border-blue-600",
@class
]}
disabled={@disabled}
{@rest}
>
<%= render_slot(@inner_block) %>
</button>
"""

View file

@ -187,17 +187,28 @@ defmodule LivebookWeb.FormComponents do
>
<%= @label %>
</span>
<label class={["switch-button", @disabled && "switch-button--disabled"]}>
<label class={[
"relative inline-block w-14 h-7 select-none",
@disabled && "pointer-events-none opacity-50"
]}>
<input type="hidden" value={@unchecked_value} name={@name} />
<input
type="checkbox"
value={@checked_value}
class="switch-button__checkbox"
class={[
"appearance-none absolute block w-7 h-7 rounded-full bg-white border-[5px] border-gray-200 cursor-pointer transition-all duration-300",
"peer checked:bg-white checked:border-blue-600 checked:translate-x-full"
]}
name={@name}
id={@id || @name}
checked={to_string(@value) == @checked_value}
{@rest}
/>
<div class="switch-button__bg"></div>
<div class={[
"block h-full w-full rounded-full bg-gray-200 cursor-pointer transition-all duration-300",
"peer-checked:bg-blue-600"
]}>
</div>
</label>
</div>
<.error :for={msg <- @errors}><%= msg %></.error>
@ -228,9 +239,8 @@ defmodule LivebookWeb.FormComponents do
<label :for={{value, description} <- @options} class="flex items-center gap-2 cursor-pointer">
<input
type="radio"
class="radio-base"
class="radio"
name={@name}
id={@id || @name}
value={value}
checked={to_string(@value) == value}
{@rest}

View file

@ -43,18 +43,19 @@ defmodule LivebookWeb.EnvVarsComponent do
<.remix_icon icon="more-2-fill" class="text-xl" />
</button>
</:toggle>
<:content>
<.menu_item>
<button
id={"env-var-#{@env_var.name}-edit"}
type="button"
phx-click={JS.push("edit_env_var", value: %{env_var: @env_var.name})}
phx-target={@target}
role="menuitem"
class="menu-item text-gray-600"
>
<.remix_icon icon="file-edit-line" />
<span class="font-medium"><%= @edit_label %></span>
<span><%= @edit_label %></span>
</button>
</.menu_item>
<.menu_item variant={:danger}>
<button
id={"env-var-#{@env_var.name}-delete"}
type="button"
@ -69,12 +70,11 @@ defmodule LivebookWeb.EnvVarsComponent do
}
phx-target={@target}
role="menuitem"
class="menu-item text-red-600"
>
<.remix_icon icon="delete-bin-line" />
<span class="font-medium">Delete</span>
<span>Delete</span>
</button>
</:content>
</.menu_item>
</.menu>
</div>
</div>

View file

@ -249,35 +249,34 @@ defmodule LivebookWeb.FileSelectComponent do
<.file_system_icon file_system={@file.file_system} />
</button>
</:toggle>
<:content>
<%= for {file_system_id, file_system} <- @file_systems do %>
<%= if file_system == @file.file_system do %>
<button class="menu-item text-gray-900" role="menuitem">
<%= for {file_system_id, file_system} <- @file_systems do %>
<%= if file_system == @file.file_system do %>
<.menu_item variant={:selected}>
<button role="menuitem">
<.file_system_icon file_system={file_system} />
<span class="font-medium"><%= file_system_label(file_system) %></span>
<span><%= file_system_label(file_system) %></span>
</button>
<% else %>
</.menu_item>
<% else %>
<.menu_item>
<button
class="menu-item text-gray-500"
role="menuitem"
phx-target={@myself}
phx-click="set_file_system"
phx-value-id={file_system_id}
>
<.file_system_icon file_system={file_system} />
<span class="font-medium"><%= file_system_label(file_system) %></span>
<span><%= file_system_label(file_system) %></span>
</button>
<% end %>
</.menu_item>
<% end %>
<.link
navigate={~p"/settings"}
class="menu-item text-gray-500 border-t border-gray-200"
role="menuitem"
>
<% end %>
<.menu_item>
<.link navigate={~p"/settings"} class="border-t border-gray-200" role="menuitem">
<.remix_icon icon="settings-3-line" />
<span class="font-medium">Configure</span>
<span>Configure</span>
</.link>
</:content>
</.menu_item>
</.menu>
"""
end
@ -357,34 +356,32 @@ defmodule LivebookWeb.FileSelectComponent do
</span>
</button>
</:toggle>
<:content>
<%= if @file_info.editable do %>
<button
type="button"
class="menu-item text-gray-500"
role="menuitem"
aria-label="rename file"
phx-click="rename_file"
phx-target={@myself}
phx-value-path={@file_info.file.path}
>
<.remix_icon icon="edit-line" />
<span class="font-medium">Rename</span>
</button>
<button
type="button"
class="menu-item text-red-600"
role="menuitem"
aria-label="delete file"
phx-click="delete_file"
phx-target={@myself}
phx-value-path={@file_info.file.path}
>
<.remix_icon icon="delete-bin-6-line" />
<span class="font-medium">Delete</span>
</button>
<% end %>
</:content>
<.menu_item :if={@file_info.editable}>
<button
type="button"
role="menuitem"
aria-label="rename file"
phx-click="rename_file"
phx-target={@myself}
phx-value-path={@file_info.file.path}
>
<.remix_icon icon="edit-line" />
<span>Rename</span>
</button>
</.menu_item>
<.menu_item :if={@file_info.editable} variant={:danger}>
<button
type="button"
role="menuitem"
aria-label="delete file"
phx-click="delete_file"
phx-target={@myself}
phx-value-path={@file_info.file.path}
>
<.remix_icon icon="delete-bin-6-line" />
<span>Delete</span>
</button>
</.menu_item>
</.menu>
"""
end

View file

@ -57,11 +57,10 @@ defmodule LivebookWeb.HomeLive.SessionListComponent do
<.remix_icon icon="arrow-down-s-line" class="text-lg leading-none align-middle ml-1" />
</button>
</:toggle>
<:content>
<.menu_item :for={order_by <- ["date", "title", "memory"]}>
<button
:for={order_by <- ["date", "title", "memory"]}
class={
"menu-item #{if order_by == @order_by, do: "text-gray-900", else: "text-gray-500"}"
"#{if order_by == @order_by, do: "text-gray-900", else: "text-gray-500"}"
}
type="button"
role="menuitem"
@ -71,9 +70,9 @@ defmodule LivebookWeb.HomeLive.SessionListComponent do
}
>
<.remix_icon icon={order_by_icon(order_by)} />
<span class="font-medium"><%= order_by_label(order_by) %></span>
<span><%= order_by_label(order_by) %></span>
</button>
</:content>
</.menu_item>
</.menu>
</div>
</div>
@ -122,7 +121,7 @@ defmodule LivebookWeb.HomeLive.SessionListComponent do
name="session_ids[]"
value={session.id}
aria-label={session.notebook_name}
class="checkbox-base hidden mr-3"
class="checkbox hidden mr-3"
data-el-bulk-edit-member
phx-click={JS.dispatch("lb:session_list:on_selection_change")}
/>
@ -154,18 +153,18 @@ defmodule LivebookWeb.HomeLive.SessionListComponent do
<.remix_icon icon="more-2-fill" class="text-xl" />
</button>
</:toggle>
<:content>
<.menu_item>
<a
class="menu-item text-gray-500"
role="menuitem"
href={~p"/sessions/#{session.id}/export/download/livemd?include_outputs=false"}
download
>
<.remix_icon icon="download-2-line" class="text-lg" />
<span class="font-medium">Download source</span>
<.remix_icon icon="download-2-line" />
<span>Download source</span>
</a>
</.menu_item>
<.menu_item>
<button
class="menu-item text-gray-500"
type="button"
role="menuitem"
phx-click="fork_session"
@ -173,38 +172,33 @@ defmodule LivebookWeb.HomeLive.SessionListComponent do
phx-value-id={session.id}
>
<.remix_icon icon="git-branch-line" />
<span class="font-medium">Fork</span>
<span>Fork</span>
</button>
<a
class="menu-item text-gray-500"
role="menuitem"
href={live_dashboard_process_path(session.pid)}
target="_blank"
>
</.menu_item>
<.menu_item>
<a role="menuitem" href={live_dashboard_process_path(session.pid)} target="_blank">
<.remix_icon icon="dashboard-2-line" />
<span class="font-medium">See on Dashboard</span>
<span>See on Dashboard</span>
</a>
</.menu_item>
<.menu_item disabled={!session.memory_usage.runtime}>
<button
class="menu-item text-gray-500"
type="button"
disabled={!session.memory_usage.runtime}
role="menuitem"
phx-target={@myself}
phx-click={toggle_edit(:off) |> JS.push("disconnect_runtime")}
phx-value-id={session.id}
>
<.remix_icon icon="shut-down-line" />
<span class="font-medium">Disconnect runtime</span>
<span>Disconnect runtime</span>
</button>
<.link
patch={~p"/home/sessions/#{session.id}/close"}
class="menu-item text-red-600"
role="menuitem"
>
</.menu_item>
<.menu_item variant={:danger}>
<.link patch={~p"/home/sessions/#{session.id}/close"} role="menuitem">
<.remix_icon icon="close-circle-line" />
<span class="font-medium">Close</span>
<span>Close</span>
</.link>
</:content>
</.menu_item>
</.menu>
</div>
</div>
@ -278,37 +272,43 @@ defmodule LivebookWeb.HomeLive.SessionListComponent do
<.remix_icon icon="arrow-down-s-line" class="text-lg leading-none align-middle ml-1" />
</button>
</:toggle>
<:content>
<button class="menu-item text-gray-600" phx-click={toggle_edit(:off)} type="button">
<.menu_item>
<button class="text-gray-600" phx-click={toggle_edit(:off)} type="button">
<.remix_icon icon="close-line" />
<span class="font-medium">Cancel</span>
<span>Cancel</span>
</button>
<button class="menu-item text-gray-600" phx-click={select_all()} type="button">
</.menu_item>
<.menu_item>
<button class="text-gray-600" phx-click={select_all()} type="button">
<.remix_icon icon="checkbox-multiple-line" />
<span class="font-medium">Select all</span>
<span>Select all</span>
</button>
</.menu_item>
<.menu_item>
<button
class="menu-item text-gray-600"
class="text-gray-600"
name="disconnect"
type="button"
data-keep-attribute="disabled"
phx-click={set_action("disconnect")}
>
<.remix_icon icon="shut-down-line" />
<span class="font-medium">Disconnect runtime</span>
<span>Disconnect runtime</span>
</button>
</.menu_item>
<.menu_item>
<button
class="menu-item text-red-600"
class="text-red-600"
name="close_all"
type="button"
data-keep-attribute="disabled"
phx-click={set_action("close_all")}
>
<.remix_icon icon="close-circle-line" />
<span class="font-medium">Close sessions</span>
<span>Close sessions</span>
</button>
<input id="bulk-action-input" class="hidden" type="text" name="action" />
</:content>
</.menu_item>
</.menu>
</div>
"""

View file

@ -82,13 +82,19 @@ defmodule LivebookWeb.Hub.NewLive do
~H"""
<div
id={@id}
class={["flex card-item flex-col", card_item_bg_color(@id, @selected)]}
class="flex flex-col cursor-pointer"
phx-click={JS.push("select_type", value: %{value: @id})}
>
<div class="flex items-center justify-center card-item-logo p-6 border-2 rounded-t-2xl h-[150px]">
<div class={[
"flex items-center justify-center p-6 border-2 rounded-t-2xl h-[150px]",
if(@id == @selected, do: "border-gray-200", else: "border-gray-100")
]}>
<%= render_slot(@logo) %>
</div>
<div class="card-item-body px-6 py-4 rounded-b-2xl grow">
<div class={[
"px-6 py-4 rounded-b-2xl grow",
if(@id == @selected, do: "bg-gray-200", else: "bg-gray-100")
]}>
<p class="text-gray-800 font-semibold cursor-pointer">
<%= @title %>
</p>
@ -101,9 +107,6 @@ defmodule LivebookWeb.Hub.NewLive do
"""
end
defp card_item_bg_color(id, selected) when id == selected, do: "selected"
defp card_item_bg_color(_id, _selected), do: ""
@impl true
def handle_event("select_type", %{"value" => service}, socket) do
{:noreply, assign(socket, selected_type: service)}

View file

@ -66,9 +66,13 @@ defmodule LivebookWeb.Output.ImageInputComponent do
<span>Open camera</span>
</button>
</:toggle>
<:content>
<div data-camera-list></div>
</:content>
<div data-camera-list>
<.menu_item>
<button role="menuitem" data-camera-id>
<span class="font-medium" data-label></span>
</button>
</.menu_item>
</div>
</.menu>
<button
class="hidden button-base button-gray border-transparent py-2 px-4 inline-flex text-gray-500"

View file

@ -26,10 +26,9 @@ defmodule LivebookWeb.Output.InputComponent do
def render(%{attrs: %{type: :image}} = assigns) do
~H"""
<div id={"#{@id}-form-#{@counter}"}>
<div class="input-label">
<.label>
<%= @attrs.label %>
</div>
</.label>
<.live_component
module={LivebookWeb.Output.ImageInputComponent}
id={"#{@id}-input"}
@ -47,10 +46,9 @@ defmodule LivebookWeb.Output.InputComponent do
def render(%{attrs: %{type: :audio}} = assigns) do
~H"""
<div id={"#{@id}-form-#{@counter}"}>
<div class="input-label">
<.label>
<%= @attrs.label %>
</div>
</.label>
<.live_component
module={LivebookWeb.Output.AudioInputComponent}
id={"#{@id}-input"}
@ -66,10 +64,9 @@ defmodule LivebookWeb.Output.InputComponent do
def render(%{attrs: %{type: :file}} = assigns) do
~H"""
<div id={"#{@id}-form-#{@counter}"}>
<div class="input-label">
<.label>
<%= @attrs.label %>
</div>
</.label>
<.live_component
module={LivebookWeb.Output.FileInputComponent}
id={"#{@id}-input"}
@ -88,10 +85,9 @@ defmodule LivebookWeb.Output.InputComponent do
def render(assigns) do
~H"""
<form id={"#{@id}-form-#{@counter}"} phx-change="change" phx-submit="submit" phx-target={@myself}>
<div class="input-label">
<.label>
<%= @attrs.label %>
</div>
</.label>
<.input_output id={"#{@id}-input"} attrs={@attrs} value={@value} myself={@myself} />
</form>
"""
@ -99,7 +95,7 @@ defmodule LivebookWeb.Output.InputComponent do
defp input_output(%{attrs: %{type: :select}} = assigns) do
~H"""
<select data-el-input class="input input-select" name="value">
<select data-el-input class="input w-60" name="value">
<option
:for={{{key, label}, idx} <- Enum.with_index(@attrs.options)}
value={idx}

View file

@ -252,41 +252,36 @@ defmodule LivebookWeb.SessionLive do
<.remix_icon icon="more-2-fill" class="text-xl" />
</button>
</:toggle>
<:content>
<.link
patch={~p"/sessions/#{@session.id}/export/livemd"}
class="menu-item text-gray-500"
role="menuitem"
>
<.menu_item>
<.link patch={~p"/sessions/#{@session.id}/export/livemd"} role="menuitem">
<.remix_icon icon="download-2-line" />
<span class="font-medium">Export</span>
<span>Export</span>
</.link>
<button class="menu-item text-gray-500" role="menuitem" phx-click="erase_outputs">
</.menu_item>
<.menu_item>
<button role="menuitem" phx-click="erase_outputs">
<.remix_icon icon="eraser-fill" />
<span class="font-medium">Erase outputs</span>
<span>Erase outputs</span>
</button>
<button class="menu-item text-gray-500" role="menuitem" phx-click="fork_session">
</.menu_item>
<.menu_item>
<button role="menuitem" phx-click="fork_session">
<.remix_icon icon="git-branch-line" />
<span class="font-medium">Fork</span>
<span>Fork</span>
</button>
<a
class="menu-item text-gray-500"
role="menuitem"
href={live_dashboard_process_path(@session.pid)}
target="_blank"
>
</.menu_item>
<.menu_item>
<a role="menuitem" href={live_dashboard_process_path(@session.pid)} target="_blank">
<.remix_icon icon="dashboard-2-line" />
<span class="font-medium">See on Dashboard</span>
<span>See on Dashboard</span>
</a>
<.link
navigate={~p"/home/sessions/#{@session.id}/close"}
class="menu-item text-gray-900"
role="menuitem"
>
</.menu_item>
<.menu_item variant={:danger}>
<.link navigate={~p"/home/sessions/#{@session.id}/close"} role="menuitem">
<.remix_icon icon="close-circle-line" />
<span class="font-medium">Close</span>
<span>Close</span>
</.link>
</:content>
</.menu_item>
</.menu>
</div>
<div>
@ -758,6 +753,7 @@ defmodule LivebookWeb.SessionLive do
</span>
<.form
:let={f}
id={"#{@prefix}-secret-#{@secret.name}-toggle"}
for={%{"toggled" => secret_toggled?(@secret, @data_secrets)}}
as={:data}
phx-change="toggle_secret"

View file

@ -322,34 +322,28 @@ defmodule LivebookWeb.SessionLive.CellComponent do
<.remix_icon icon="arrow-down-s-line" class="text-xl" />
</button>
</:toggle>
<:content>
<.menu_item variant={if(not @reevaluate_automatically, do: :selected, else: :default)}>
<button
class={[
"menu-item",
if(not @reevaluate_automatically, do: "text-gray-900", else: "text-gray-500")
]}
role="menuitem"
phx-click={
JS.push("set_reevaluate_automatically", value: %{value: false, cell_id: @cell_id})
}
>
<.remix_icon icon="check-line" class={if(@reevaluate_automatically, do: "invisible")} />
<span class="font-medium">Evaluate on demand</span>
<span>Evaluate on demand</span>
</button>
</.menu_item>
<.menu_item variant={if(@reevaluate_automatically, do: :selected, else: :default)}>
<button
class={[
"menu-item",
if(@reevaluate_automatically, do: "text-gray-900", else: "text-gray-500")
]}
role="menuitem"
phx-click={
JS.push("set_reevaluate_automatically", value: %{value: true, cell_id: @cell_id})
}
>
<.remix_icon icon="check-line" class={if(not @reevaluate_automatically, do: "invisible")} />
<span class="font-medium">Reevaluate automatically</span>
<span>Reevaluate automatically</span>
</button>
</:content>
</.menu_item>
</.menu>
</div>
"""
@ -393,18 +387,17 @@ defmodule LivebookWeb.SessionLive.CellComponent do
<.remix_icon icon="arrow-down-s-line" class="text-xl" />
</button>
</:toggle>
<:content>
<.menu_item>
<button
class="menu-item text-gray-500"
role="menuitem"
data-el-queue-cell-evaluation-button
data-cell-id={@cell_id}
data-disable-dependencies-cache
>
<.remix_icon icon="play-circle-fill" />
<span class="font-medium">Setup without cache</span>
<span>Setup without cache</span>
</button>
</:content>
</.menu_item>
</.menu>
<% end %>
</div>

View file

@ -73,17 +73,19 @@ defmodule LivebookWeb.SessionLive.IndicatorsComponent do
<.remix_icon icon="code-line" class="text-xl text-green-bright-400" />
</button>
</:toggle>
<:content>
<button class="menu-item text-gray-500" role="menuitem" data-el-code-zen-outputs-toggle>
<.menu_item>
<button role="menuitem" data-el-code-zen-outputs-toggle>
<.remix_icon icon="layout-bottom-2-line" />
<span class="font-medium" data-label-show>Show outputs</span>
<span class="font-medium" data-label-hide>Hide outputs</span>
<span data-label-show>Show outputs</span>
<span data-label-hide>Hide outputs</span>
</button>
<button class="menu-item text-gray-500" role="menuitem" data-el-code-zen-disable-button>
</.menu_item>
<.menu_item>
<button role="menuitem" data-el-code-zen-disable-button>
<.remix_icon icon="close-line" />
<span class="font-medium">Exit code zen</span>
<span>Exit code zen</span>
</button>
</:content>
</.menu_item>
</.menu>
</div>
"""

View file

@ -25,9 +25,8 @@ defmodule LivebookWeb.SessionLive.InsertButtonsComponent do
<:toggle>
<button class="button-base button-small">+ Block</button>
</:toggle>
<:content>
<.menu_item>
<button
class="menu-item text-gray-500"
role="menuitem"
phx-click="insert_cell_below"
phx-value-type="markdown"
@ -35,21 +34,23 @@ defmodule LivebookWeb.SessionLive.InsertButtonsComponent do
phx-value-cell_id={@cell_id}
>
<.remix_icon icon="markdown-fill" />
<span class="font-medium">Markdown</span>
<span>Markdown</span>
</button>
</.menu_item>
<.menu_item>
<button
class="menu-item text-gray-500"
role="menuitem"
phx-click="insert_section_below"
phx-value-section_id={@section_id}
phx-value-cell_id={@cell_id}
>
<.remix_icon icon="h-2" />
<span class="font-medium">Section</span>
<span>Section</span>
</button>
<div class="my-2 border-b border-gray-200"></div>
</.menu_item>
<div class="my-2 border-b border-gray-200"></div>
<.menu_item>
<button
class="menu-item text-gray-500"
role="menuitem"
phx-click="insert_cell_below"
phx-value-type="diagram"
@ -57,20 +58,21 @@ defmodule LivebookWeb.SessionLive.InsertButtonsComponent do
phx-value-cell_id={@cell_id}
>
<.remix_icon icon="organization-chart" />
<span class="font-medium">Diagram</span>
<span>Diagram</span>
</button>
</.menu_item>
<.menu_item>
<.link
patch={
~p"/sessions/#{@session_id}/cell-upload?section_id=#{@section_id}&cell_id=#{@cell_id || ""}"
}
class="menu-item text-gray-500"
aria-label="insert image"
role="menuitem"
>
<.remix_icon icon="image-add-line" />
<span class="font-medium">Image</span>
<span>Image</span>
</.link>
</:content>
</.menu_item>
</.menu>
<%= cond do %>
<% not Livebook.Runtime.connected?(@runtime) -> %>
@ -101,14 +103,13 @@ defmodule LivebookWeb.SessionLive.InsertButtonsComponent do
<:toggle>
<button class="button-base button-small">+ Smart</button>
</:toggle>
<:content>
<.menu_item :for={definition <- Enum.sort_by(@smart_cell_definitions, & &1.name)}>
<.smart_cell_insert_button
:for={definition <- Enum.sort_by(@smart_cell_definitions, & &1.name)}
definition={definition}
section_id={@section_id}
cell_id={@cell_id}
/>
</:content>
</.menu_item>
</.menu>
<% end %>
</div>
@ -119,31 +120,27 @@ defmodule LivebookWeb.SessionLive.InsertButtonsComponent do
defp smart_cell_insert_button(%{definition: %{requirement: %{variants: [_, _ | _]}}} = assigns) do
~H"""
<.submenu>
<button class="menu-item text-gray-500" role="menuitem">
<span class="font-medium"><%= @definition.name %></span>
</button>
<:content>
<:primary>
<button role="menuitem">
<span><%= @definition.name %></span>
</button>
</:primary>
<.menu_item :for={{variant, idx} <- Enum.with_index(@definition.requirement.variants)}>
<button
:for={{variant, idx} <- Enum.with_index(@definition.requirement.variants)}
class="menu-item text-gray-500"
role="menuitem"
phx-click={on_smart_cell_click(@definition, idx, @section_id, @cell_id)}
>
<span class="font-medium"><%= variant.name %></span>
<span><%= variant.name %></span>
</button>
</:content>
</.menu_item>
</.submenu>
"""
end
defp smart_cell_insert_button(assigns) do
~H"""
<button
class="menu-item text-gray-500"
role="menuitem"
phx-click={on_smart_cell_click(@definition, 0, @section_id, @cell_id)}
>
<span class="font-medium"><%= @definition.name %></span>
<button role="menuitem" phx-click={on_smart_cell_click(@definition, 0, @section_id, @cell_id)}>
<span><%= @definition.name %></span>
</button>
"""
end

View file

@ -43,34 +43,32 @@ defmodule LivebookWeb.SessionLive.SectionComponent do
</button>
</span>
</:toggle>
<:content>
<%= for parent <- @section_view.valid_parents do %>
<%= if @section_view.parent && @section_view.parent.id == parent.id do %>
<button
class="menu-item text-gray-900"
phx-click="unset_section_parent"
phx-value-section_id={@section_view.id}
>
<.remix_icon icon="arrow-right-s-line" />
<span class="font-medium"><%= parent.name %></span>
</button>
<% else %>
<button
class="menu-item text-gray-500"
phx-click="set_section_parent"
phx-value-section_id={@section_view.id}
phx-value-parent_id={parent.id}
>
<.remix_icon
:if={@section_view.parent && @section_view.parent.id}
icon="arrow-right-s-line"
class="invisible"
/>
<span class="font-medium"><%= parent.name %></span>
</button>
<% end %>
<.menu_item :for={parent <- @section_view.valid_parents}>
<%= if @section_view.parent && @section_view.parent.id == parent.id do %>
<button
class="text-gray-900"
phx-click="unset_section_parent"
phx-value-section_id={@section_view.id}
>
<.remix_icon icon="arrow-right-s-line" />
<span><%= parent.name %></span>
</button>
<% else %>
<button
class="text-gray-500"
phx-click="set_section_parent"
phx-value-section_id={@section_view.id}
phx-value-parent_id={parent.id}
>
<.remix_icon
:if={@section_view.parent && @section_view.parent.id}
icon="arrow-right-s-line"
class="invisible"
/>
<span><%= parent.name %></span>
</button>
<% end %>
</:content>
</.menu_item>
</.menu>
<span class="tooltip top" data-tooltip="Move up">
<button

View file

@ -61,23 +61,24 @@ defmodule LivebookWeb.SettingsLive.FileSystemsComponent do
<.remix_icon icon="more-2-fill" class="text-xl" />
</button>
</:toggle>
<:content>
<.menu_item>
<button
:if={@default_file_system_id != @file_system_id}
type="button"
role="menuitem"
class="menu-item text-gray-600"
phx-click="make_default_file_system"
phx-value-id={@file_system_id}
>
<.remix_icon icon="star-line" />
<span class="font-medium">Make default</span>
<span>Make default</span>
</button>
</.menu_item>
<.menu_item variant={:danger}>
<button
:if={@file_system_id != "local"}
type="button"
role="menuitem"
class="menu-item text-red-600"
class="text-red-600"
phx-click={
with_confirm(
JS.push("detach_file_system", value: %{id: @file_system_id}),
@ -90,9 +91,9 @@ defmodule LivebookWeb.SettingsLive.FileSystemsComponent do
}
>
<.remix_icon icon="delete-bin-line" />
<span class="font-medium">Detach</span>
<span>Detach</span>
</button>
</:content>
</.menu_item>
</.menu>
</div>
"""