mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-12-11 06:05:56 +08:00
Initial redesign (#75)
* Add Remix icons * Replace existing icons with Remix icons * Update fonts * Redesign homepage * Redesign shortcuts modal * Fix tests
This commit is contained in:
parent
266bf35bd0
commit
a2d1e2f934
30 changed files with 252 additions and 326 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
/* Buttons */
|
/* Buttons */
|
||||||
|
|
||||||
.button-base {
|
.button-base {
|
||||||
@apply px-4 py-2 bg-white rounded-md border border-gray-300 font-medium text-gray-700;
|
@apply px-5 py-2 bg-white rounded-lg border border-gray-200 font-medium text-sm text-gray-600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-base:not(:disabled) {
|
.button-base:not(:disabled) {
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-primary {
|
.button-primary {
|
||||||
@apply border-0 bg-blue-400 text-white;
|
@apply border-transparent bg-blue-600 text-white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-primary:not(:disabled) {
|
.button-primary:not(:disabled) {
|
||||||
|
|
@ -35,11 +35,11 @@
|
||||||
/* Form fields */
|
/* Form fields */
|
||||||
|
|
||||||
.input-base {
|
.input-base {
|
||||||
@apply w-full px-3 py-3 bg-white rounded-md placeholder-gray-400 text-gray-700;
|
@apply w-full p-3 bg-white border border-gray-200 rounded-lg placeholder-gray-400 text-gray-600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkbox-base {
|
.checkbox-base {
|
||||||
@apply h-5 w-5 appearance-none border border-gray-300 rounded text-blue-400 cursor-pointer;
|
@apply h-5 w-5 appearance-none border border-gray-300 rounded text-blue-600 cursor-pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkbox-base:checked {
|
.checkbox-base:checked {
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,7 @@
|
||||||
button:focus {
|
button:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: "Inter";
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,14 +99,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown code {
|
.markdown code {
|
||||||
@apply py-1 px-2 rounded-md text-sm align-middle;
|
@apply py-1 px-2 rounded-lg text-sm align-middle font-mono;
|
||||||
/* Match the editor colors */
|
/* Match the editor colors */
|
||||||
background-color: #282c34;
|
background-color: #282c34;
|
||||||
color: #abb2bf;
|
color: #abb2bf;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown pre > code {
|
.markdown pre > code {
|
||||||
@apply block p-4 rounded-md text-sm align-middle;
|
@apply block p-4 rounded-lg text-sm align-middle font-mono;
|
||||||
/* Match the editor colors */
|
/* Match the editor colors */
|
||||||
background-color: #282c34;
|
background-color: #282c34;
|
||||||
color: #abb2bf;
|
color: #abb2bf;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.font-editor {
|
.font-editor {
|
||||||
font-family: "Droid Sans Mono", monospace, monospace, "Droid Sans Fallback";
|
font-family: "JetBrains Mono";
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,10 @@
|
||||||
import "../css/app.css";
|
import "../css/app.css";
|
||||||
|
import 'remixicon/fonts/remixicon.css'
|
||||||
|
|
||||||
|
import "@fontsource/inter";
|
||||||
|
import "@fontsource/inter/500.css";
|
||||||
|
import "@fontsource/inter/600.css";
|
||||||
|
import "@fontsource/jetbrains-mono";
|
||||||
|
|
||||||
import "phoenix_html";
|
import "phoenix_html";
|
||||||
import { Socket } from "phoenix";
|
import { Socket } from "phoenix";
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ class LiveEditor {
|
||||||
occurrencesHighlight: false,
|
occurrencesHighlight: false,
|
||||||
renderLineHighlight: "none",
|
renderLineHighlight: "none",
|
||||||
theme: "custom",
|
theme: "custom",
|
||||||
|
fontFamily: "JetBrains Mono"
|
||||||
});
|
});
|
||||||
|
|
||||||
this.editor.getModel().updateOptions({
|
this.editor.getModel().updateOptions({
|
||||||
|
|
|
||||||
35
assets/package-lock.json
generated
35
assets/package-lock.json
generated
|
|
@ -6,6 +6,8 @@
|
||||||
"": {
|
"": {
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fontsource/inter": "^4.2.2",
|
||||||
|
"@fontsource/jetbrains-mono": "^4.2.2",
|
||||||
"dompurify": "^2.2.6",
|
"dompurify": "^2.2.6",
|
||||||
"hyperlist": "^1.0.0",
|
"hyperlist": "^1.0.0",
|
||||||
"marked": "^1.2.8",
|
"marked": "^1.2.8",
|
||||||
|
|
@ -14,7 +16,8 @@
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"phoenix": "file:../deps/phoenix",
|
"phoenix": "file:../deps/phoenix",
|
||||||
"phoenix_html": "file:../deps/phoenix_html",
|
"phoenix_html": "file:../deps/phoenix_html",
|
||||||
"phoenix_live_view": "file:../deps/phoenix_live_view"
|
"phoenix_live_view": "file:../deps/phoenix_live_view",
|
||||||
|
"remixicon": "^2.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.0.0",
|
"@babel/core": "^7.0.0",
|
||||||
|
|
@ -1095,6 +1098,16 @@
|
||||||
"node": ">=0.1.95"
|
"node": ">=0.1.95"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@fontsource/inter": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-lvR1PQe+8FTTd3YRW84KGcgUR8leZ7S3aY+51MQ90MQHI0VQe3cDH6T6jjs1qTm+wPmWfdSVjN8ugvNZpGUnvA=="
|
||||||
|
},
|
||||||
|
"node_modules/@fontsource/jetbrains-mono": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fontsource/jetbrains-mono/-/jetbrains-mono-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-aCwLIqfZZrZjy+cIx/9hSzxyOcz8YzMbd3VQ8QRkS2MB3+XsXAnMLEkELXLCfKYUkEysRECaq5s7+Qhi1hgZAA=="
|
||||||
|
},
|
||||||
"node_modules/@fullhuman/postcss-purgecss": {
|
"node_modules/@fullhuman/postcss-purgecss": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-3.1.3.tgz",
|
||||||
|
|
@ -13059,6 +13072,11 @@
|
||||||
"jsesc": "bin/jsesc"
|
"jsesc": "bin/jsesc"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/remixicon": {
|
||||||
|
"version": "2.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/remixicon/-/remixicon-2.5.0.tgz",
|
||||||
|
"integrity": "sha512-q54ra2QutYDZpuSnFjmeagmEiN9IMo56/zz5dDNitzKD23oFRw77cWo4TsrAdmdkPiEn8mxlrTqxnkujDbEGww=="
|
||||||
|
},
|
||||||
"node_modules/remove-trailing-separator": {
|
"node_modules/remove-trailing-separator": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
||||||
|
|
@ -16690,6 +16708,16 @@
|
||||||
"minimist": "^1.2.0"
|
"minimist": "^1.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@fontsource/inter": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-lvR1PQe+8FTTd3YRW84KGcgUR8leZ7S3aY+51MQ90MQHI0VQe3cDH6T6jjs1qTm+wPmWfdSVjN8ugvNZpGUnvA=="
|
||||||
|
},
|
||||||
|
"@fontsource/jetbrains-mono": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fontsource/jetbrains-mono/-/jetbrains-mono-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-aCwLIqfZZrZjy+cIx/9hSzxyOcz8YzMbd3VQ8QRkS2MB3+XsXAnMLEkELXLCfKYUkEysRECaq5s7+Qhi1hgZAA=="
|
||||||
|
},
|
||||||
"@fullhuman/postcss-purgecss": {
|
"@fullhuman/postcss-purgecss": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-3.1.3.tgz",
|
||||||
|
|
@ -26530,6 +26558,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"remixicon": {
|
||||||
|
"version": "2.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/remixicon/-/remixicon-2.5.0.tgz",
|
||||||
|
"integrity": "sha512-q54ra2QutYDZpuSnFjmeagmEiN9IMo56/zz5dDNitzKD23oFRw77cWo4TsrAdmdkPiEn8mxlrTqxnkujDbEGww=="
|
||||||
|
},
|
||||||
"remove-trailing-separator": {
|
"remove-trailing-separator": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
"test:watch": "jest --watch"
|
"test:watch": "jest --watch"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fontsource/inter": "^4.2.2",
|
||||||
|
"@fontsource/jetbrains-mono": "^4.2.2",
|
||||||
"dompurify": "^2.2.6",
|
"dompurify": "^2.2.6",
|
||||||
"hyperlist": "^1.0.0",
|
"hyperlist": "^1.0.0",
|
||||||
"marked": "^1.2.8",
|
"marked": "^1.2.8",
|
||||||
|
|
@ -18,7 +20,8 @@
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"phoenix": "file:../deps/phoenix",
|
"phoenix": "file:../deps/phoenix",
|
||||||
"phoenix_html": "file:../deps/phoenix_html",
|
"phoenix_html": "file:../deps/phoenix_html",
|
||||||
"phoenix_live_view": "file:../deps/phoenix_live_view"
|
"phoenix_live_view": "file:../deps/phoenix_live_view",
|
||||||
|
"remixicon": "^2.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.0.0",
|
"@babel/core": "^7.0.0",
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,38 @@ module.exports = {
|
||||||
],
|
],
|
||||||
darkMode: false,
|
darkMode: false,
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
fontFamily: {
|
||||||
|
'sans': ['Inter'],
|
||||||
|
'mono': ['JetBrains Mono'],
|
||||||
|
},
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
blue: {
|
||||||
|
50: '#F5F7FF',
|
||||||
|
100: '#ECF0FF',
|
||||||
|
200: '#D8E0FF',
|
||||||
|
300: '#B2C1FF',
|
||||||
|
400: '#8BA2FF',
|
||||||
|
500: '#6583FF',
|
||||||
|
600: '#3E64FF',
|
||||||
|
700: '#2D4CDB',
|
||||||
|
800: '#1F37B7',
|
||||||
|
900: '#132593',
|
||||||
|
},
|
||||||
|
gray: {
|
||||||
|
50: '#F8FAFC',
|
||||||
|
100: '#F0F5F9',
|
||||||
|
200: '#E1E8F0',
|
||||||
|
300: '#CAD5E0',
|
||||||
|
400: '#91A4B7',
|
||||||
|
500: '#61758A',
|
||||||
|
600: '#445668',
|
||||||
|
700: '#304254',
|
||||||
|
800: '#1C2A3A',
|
||||||
|
900: '#0D1829',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
variants: {
|
variants: {
|
||||||
extend: {},
|
extend: {},
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ module.exports = (env, options) => {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.ttf$/,
|
test: /\.(ttf|woff|woff2|eot|svg)$/,
|
||||||
use: ['file-loader'],
|
use: ['file-loader'],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,6 @@ defmodule LivebookWeb do
|
||||||
|
|
||||||
# Custom helpers
|
# Custom helpers
|
||||||
import LivebookWeb.Helpers
|
import LivebookWeb.Helpers
|
||||||
alias LivebookWeb.Icons
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
defmodule LivebookWeb.Helpers do
|
defmodule LivebookWeb.Helpers do
|
||||||
import Phoenix.LiveView.Helpers
|
import Phoenix.LiveView.Helpers
|
||||||
|
import Phoenix.HTML.Tag
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Renders a component inside the `Livebook.ModalComponent` component.
|
Renders a component inside the `Livebook.ModalComponent` component.
|
||||||
|
|
@ -31,4 +32,13 @@ defmodule LivebookWeb.Helpers do
|
||||||
defp windows?(user_agent), do: String.match?(user_agent, ~r/Windows/)
|
defp windows?(user_agent), do: String.match?(user_agent, ~r/Windows/)
|
||||||
|
|
||||||
defdelegate ansi_string_to_html(string), to: LivebookWeb.ANSI
|
defdelegate ansi_string_to_html(string), to: LivebookWeb.ANSI
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns [Remix](https://remixicon.com) icon tag.
|
||||||
|
"""
|
||||||
|
def remix_icon(name, attrs \\ []) do
|
||||||
|
icon_class = "ri-#{name}"
|
||||||
|
attrs = Keyword.update(attrs, :class, icon_class, fn class -> "#{icon_class} #{class}" end)
|
||||||
|
content_tag(:i, "", attrs)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -17,25 +17,25 @@ defmodule LivebookWeb.CellComponent do
|
||||||
def render_cell_content(%{cell: %{type: :markdown}} = assigns) do
|
def render_cell_content(%{cell: %{type: :markdown}} = assigns) do
|
||||||
~L"""
|
~L"""
|
||||||
<div class="flex flex-col items-center space-y-2 absolute z-50 right-0 top-0 -mr-10" data-element="actions">
|
<div class="flex flex-col items-center space-y-2 absolute z-50 right-0 top-0 -mr-10" data-element="actions">
|
||||||
<button class="text-gray-500 hover:text-current" data-element="enable-insert-mode-button">
|
<button class="text-gray-400 hover:text-current" data-element="enable-insert-mode-button">
|
||||||
<%= Icons.svg(:pencil, class: "h-6") %>
|
<%= remix_icon("pencil-line", class: "text-2xl") %>
|
||||||
</button>
|
</button>
|
||||||
<button class="text-gray-500 hover:text-current"
|
<button class="text-gray-400 hover:text-current"
|
||||||
phx-click="delete_cell"
|
phx-click="delete_cell"
|
||||||
phx-value-cell_id="<%= @cell.id %>">
|
phx-value-cell_id="<%= @cell.id %>">
|
||||||
<%= Icons.svg(:trash, class: "h-6") %>
|
<%= remix_icon("delete-bin-line", class: "text-2xl") %>
|
||||||
</button>
|
</button>
|
||||||
<button class="text-gray-500 hover:text-current"
|
<button class="text-gray-400 hover:text-current"
|
||||||
phx-click="move_cell"
|
phx-click="move_cell"
|
||||||
phx-value-cell_id="<%= @cell.id %>"
|
phx-value-cell_id="<%= @cell.id %>"
|
||||||
phx-value-offset="-1">
|
phx-value-offset="-1">
|
||||||
<%= Icons.svg(:chevron_up, class: "h-6") %>
|
<%= remix_icon("arrow-up-s-line", class: "text-2xl") %>
|
||||||
</button>
|
</button>
|
||||||
<button class="text-gray-500 hover:text-current"
|
<button class="text-gray-400 hover:text-current"
|
||||||
phx-click="move_cell"
|
phx-click="move_cell"
|
||||||
phx-value-cell_id="<%= @cell.id %>"
|
phx-value-cell_id="<%= @cell.id %>"
|
||||||
phx-value-offset="1">
|
phx-value-offset="1">
|
||||||
<%= Icons.svg(:chevron_down, class: "h-6") %>
|
<%= remix_icon("arrow-down-s-line", class: "text-2xl") %>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -53,37 +53,37 @@ defmodule LivebookWeb.CellComponent do
|
||||||
~L"""
|
~L"""
|
||||||
<div class="flex flex-col items-center space-y-2 absolute z-50 right-0 top-0 -mr-10" data-element="actions">
|
<div class="flex flex-col items-center space-y-2 absolute z-50 right-0 top-0 -mr-10" data-element="actions">
|
||||||
<%= if @cell_info.evaluation_status == :ready do %>
|
<%= if @cell_info.evaluation_status == :ready do %>
|
||||||
<button class="text-gray-500 hover:text-current"
|
<button class="text-gray-400 hover:text-current"
|
||||||
phx-click="queue_cell_evaluation"
|
phx-click="queue_cell_evaluation"
|
||||||
phx-value-cell_id="<%= @cell.id %>">
|
phx-value-cell_id="<%= @cell.id %>">
|
||||||
<%= Icons.svg(:play, class: "h-6") %>
|
<%= remix_icon("play-circle-line", class: "text-2xl") %>
|
||||||
</button>
|
</button>
|
||||||
<% else %>
|
<% else %>
|
||||||
<button class="text-gray-500 hover:text-current"
|
<button class="text-gray-400 hover:text-current"
|
||||||
phx-click="cancel_cell_evaluation"
|
phx-click="cancel_cell_evaluation"
|
||||||
phx-value-cell_id="<%= @cell.id %>">
|
phx-value-cell_id="<%= @cell.id %>">
|
||||||
<%= Icons.svg(:stop, class: "h-6") %>
|
<%= remix_icon("stop-circle-line", class: "text-2xl") %>
|
||||||
</button>
|
</button>
|
||||||
<% end %>
|
<% end %>
|
||||||
<button class="text-gray-500 hover:text-current"
|
<button class="text-gray-400 hover:text-current"
|
||||||
phx-click="delete_cell"
|
phx-click="delete_cell"
|
||||||
phx-value-cell_id="<%= @cell.id %>">
|
phx-value-cell_id="<%= @cell.id %>">
|
||||||
<%= Icons.svg(:trash, class: "h-6") %>
|
<%= remix_icon("delete-bin-line", class: "text-2xl") %>
|
||||||
</button>
|
</button>
|
||||||
<%= live_patch to: Routes.session_path(@socket, :cell_settings, @session_id, @cell.id), class: "text-gray-500 hover:text-current" do %>
|
<%= live_patch to: Routes.session_path(@socket, :cell_settings, @session_id, @cell.id), class: "text-gray-400 hover:text-current" do %>
|
||||||
<%= Icons.svg(:adjustments, class: "h-6") %>
|
<%= remix_icon("list-settings-line", class: "text-2xl") %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<button class="text-gray-500 hover:text-current"
|
<button class="text-gray-400 hover:text-current"
|
||||||
phx-click="move_cell"
|
phx-click="move_cell"
|
||||||
phx-value-cell_id="<%= @cell.id %>"
|
phx-value-cell_id="<%= @cell.id %>"
|
||||||
phx-value-offset="-1">
|
phx-value-offset="-1">
|
||||||
<%= Icons.svg(:chevron_up, class: "h-6") %>
|
<%= remix_icon("arrow-up-s-line", class: "text-2xl") %>
|
||||||
</button>
|
</button>
|
||||||
<button class="text-gray-500 hover:text-current"
|
<button class="text-gray-400 hover:text-current"
|
||||||
phx-click="move_cell"
|
phx-click="move_cell"
|
||||||
phx-value-cell_id="<%= @cell.id %>"
|
phx-value-cell_id="<%= @cell.id %>"
|
||||||
phx-value-offset="1">
|
phx-value-offset="1">
|
||||||
<%= Icons.svg(:chevron_down, class: "h-6") %>
|
<%= remix_icon("arrow-down-s-line", class: "text-2xl") %>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -102,7 +102,7 @@ defmodule LivebookWeb.CellComponent do
|
||||||
assigns = %{cell: cell, cell_info: cell_info, show_status: show_status}
|
assigns = %{cell: cell, cell_info: cell_info, show_status: show_status}
|
||||||
|
|
||||||
~L"""
|
~L"""
|
||||||
<div class="py-3 rounded-md overflow-hidden bg-editor relative">
|
<div class="py-3 rounded-lg overflow-hidden bg-editor relative">
|
||||||
<div
|
<div
|
||||||
id="editor-container-<%= @cell.id %>"
|
id="editor-container-<%= @cell.id %>"
|
||||||
data-element="editor-container"
|
data-element="editor-container"
|
||||||
|
|
@ -137,9 +137,9 @@ defmodule LivebookWeb.CellComponent do
|
||||||
~L"""
|
~L"""
|
||||||
<div class="max-w-2xl w-full animate-pulse">
|
<div class="max-w-2xl w-full animate-pulse">
|
||||||
<div class="flex-1 space-y-4">
|
<div class="flex-1 space-y-4">
|
||||||
<div class="h-4 bg-gray-200 rounded-md w-3/4"></div>
|
<div class="h-4 bg-gray-200 rounded-lg w-3/4"></div>
|
||||||
<div class="h-4 bg-gray-200 rounded-md"></div>
|
<div class="h-4 bg-gray-200 rounded-lg"></div>
|
||||||
<div class="h-4 bg-gray-200 rounded-md w-5/6"></div>
|
<div class="h-4 bg-gray-200 rounded-lg w-5/6"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
|
|
@ -159,9 +159,9 @@ defmodule LivebookWeb.CellComponent do
|
||||||
~L"""
|
~L"""
|
||||||
<div class="px-8 max-w-2xl w-full animate-pulse">
|
<div class="px-8 max-w-2xl w-full animate-pulse">
|
||||||
<div class="flex-1 space-y-4 py-1">
|
<div class="flex-1 space-y-4 py-1">
|
||||||
<div class="h-4 bg-gray-500 rounded-md w-3/4"></div>
|
<div class="h-4 bg-gray-500 rounded-lg w-3/4"></div>
|
||||||
<div class="h-4 bg-gray-500 rounded-md"></div>
|
<div class="h-4 bg-gray-500 rounded-lg"></div>
|
||||||
<div class="h-4 bg-gray-500 rounded-md w-5/6"></div>
|
<div class="h-4 bg-gray-500 rounded-lg w-5/6"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
|
|
@ -171,7 +171,7 @@ defmodule LivebookWeb.CellComponent do
|
||||||
assigns = %{outputs: outputs, cell_id: cell_id}
|
assigns = %{outputs: outputs, cell_id: cell_id}
|
||||||
|
|
||||||
~L"""
|
~L"""
|
||||||
<div class="flex flex-col rounded-md border border-gray-200 divide-y divide-gray-200 font-editor">
|
<div class="flex flex-col rounded-lg border border-gray-200 divide-y divide-gray-200 font-editor">
|
||||||
<%= for {output, index} <- @outputs |> Enum.reverse() |> Enum.with_index() do %>
|
<%= for {output, index} <- @outputs |> Enum.reverse() |> Enum.with_index() do %>
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<div class="">
|
<div class="">
|
||||||
|
|
@ -230,7 +230,7 @@ defmodule LivebookWeb.CellComponent do
|
||||||
<div class="text-xs text-gray-400">Evaluating</div>
|
<div class="text-xs text-gray-400">Evaluating</div>
|
||||||
<span class="flex relative h-3 w-3">
|
<span class="flex relative h-3 w-3">
|
||||||
<span class="animate-ping absolute inline-flex h-3 w-3 rounded-full bg-blue-300 opacity-75"></span>
|
<span class="animate-ping absolute inline-flex h-3 w-3 rounded-full bg-blue-300 opacity-75"></span>
|
||||||
<span class="relative inline-flex rounded-full h-3 w-3 bg-blue-400"></span>
|
<span class="relative inline-flex rounded-full h-3 w-3 bg-blue-600"></span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -17,17 +17,14 @@ defmodule LivebookWeb.HomeLive do
|
||||||
@impl true
|
@impl true
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~L"""
|
~L"""
|
||||||
<header class="flex justify-center p-4 border-b">
|
<div class="container max-w-4xl w-full mx-auto p-4 pb-8 flex flex-col items-center space-y-4">
|
||||||
<h1 class="text-2xl font-medium">Livebook</h1>
|
|
||||||
</header>
|
|
||||||
<div class="container max-w-5xl w-full mx-auto p-4 pb-8 flex flex-col items-center space-y-4">
|
|
||||||
<div class="w-full flex justify-end">
|
<div class="w-full flex justify-end">
|
||||||
<button class="button-base button-sm"
|
<button class="button-base button-primary"
|
||||||
phx-click="new">
|
phx-click="new">
|
||||||
New notebook
|
New Notebook
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="container flex flex-col space-y-4">
|
<div class="w-full flex flex-col space-y-4">
|
||||||
<%= live_component @socket, LivebookWeb.PathSelectComponent,
|
<%= live_component @socket, LivebookWeb.PathSelectComponent,
|
||||||
id: "path_select",
|
id: "path_select",
|
||||||
path: @path,
|
path: @path,
|
||||||
|
|
@ -35,27 +32,30 @@ defmodule LivebookWeb.HomeLive do
|
||||||
running_paths: paths(@session_summaries),
|
running_paths: paths(@session_summaries),
|
||||||
target: nil %>
|
target: nil %>
|
||||||
<div class="flex justify-end space-x-2">
|
<div class="flex justify-end space-x-2">
|
||||||
<%= content_tag :button, "Fork",
|
<%= content_tag :button,
|
||||||
class: "button-base button-sm",
|
class: "button-base",
|
||||||
phx_click: "fork",
|
phx_click: "fork",
|
||||||
disabled: not path_forkable?(@path) %>
|
disabled: not path_forkable?(@path) do %>
|
||||||
|
<%= remix_icon("git-branch-line", class: "align-middle mr-1") %>
|
||||||
|
<span>Fork</span>
|
||||||
|
<% end %>
|
||||||
<%= if path_running?(@path, @session_summaries) do %>
|
<%= if path_running?(@path, @session_summaries) do %>
|
||||||
<%= live_patch "Join session", to: Routes.session_path(@socket, :page, session_id_by_path(@path, @session_summaries)),
|
<%= live_patch "Join session", to: Routes.session_path(@socket, :page, session_id_by_path(@path, @session_summaries)),
|
||||||
class: "button-base button-sm button-primary" %>
|
class: "button-base button-primary" %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= content_tag :button, "Open",
|
<%= content_tag :button, "Open",
|
||||||
class: "button-base button-sm button-primary",
|
class: "button-base button-primary",
|
||||||
phx_click: "open",
|
phx_click: "open",
|
||||||
disabled: not path_openable?(@path, @session_summaries) %>
|
disabled: not path_openable?(@path, @session_summaries) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full pt-24">
|
<div class="w-full pt-24">
|
||||||
<h3 class="text-xl font-medium text-gray-900">
|
<h3 class="text-xl font-semibold text-gray-800 mb-5">
|
||||||
Running sessions
|
Running Sessions
|
||||||
</h3>
|
</h3>
|
||||||
<%= if @session_summaries == [] do %>
|
<%= if @session_summaries == [] do %>
|
||||||
<div class="mt-3 text-gray-500 text-medium">
|
<div class="text-gray-500 text-medium">
|
||||||
No sessions currently running, you can create one above.
|
No sessions currently running, you can create one above.
|
||||||
</div>
|
</div>
|
||||||
<% else %>
|
<% else %>
|
||||||
|
|
|
||||||
|
|
@ -1,193 +0,0 @@
|
||||||
defmodule LivebookWeb.Icons do
|
|
||||||
import Phoenix.HTML.Tag
|
|
||||||
import Phoenix.LiveView.Helpers
|
|
||||||
|
|
||||||
@doc """
|
|
||||||
Returns icon svg tag.
|
|
||||||
"""
|
|
||||||
def svg(name, attrs \\ [])
|
|
||||||
|
|
||||||
def svg(:play, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" />
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:plus, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:trash, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:chip, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:information_circle, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:exclamation_circle, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:question_mark_circle, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:pencil, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:folder, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:document_text, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:check_circle, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:dots_circle_horizontal, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:home, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:stop, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 10a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 01-1-1v-4z" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:chevron_up, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:chevron_down, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def svg(:adjustments, attrs) do
|
|
||||||
assigns = %{attrs: heroicon_svg_attrs(attrs)}
|
|
||||||
|
|
||||||
~L"""
|
|
||||||
<%= tag(:svg, @attrs) %>
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4" />
|
|
||||||
</svg>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
# https://heroicons.com
|
|
||||||
defp heroicon_svg_attrs(attrs) do
|
|
||||||
heroicon_svg_attrs = [
|
|
||||||
xmlns: "http://www.w3.org/2000/svg",
|
|
||||||
fill: "none",
|
|
||||||
viewBox: "0 0 24 24",
|
|
||||||
stroke: "currentColor"
|
|
||||||
]
|
|
||||||
|
|
||||||
Keyword.merge(attrs, heroicon_svg_attrs)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -5,14 +5,14 @@ defmodule LivebookWeb.InsertCellComponent do
|
||||||
~L"""
|
~L"""
|
||||||
<div class="<%= if(@persistent, do: "opacity-100", else: "opacity-0") %> hover:opacity-100 flex space-x-2 justify-center items-center">
|
<div class="<%= if(@persistent, do: "opacity-100", else: "opacity-0") %> hover:opacity-100 flex space-x-2 justify-center items-center">
|
||||||
<%= line() %>
|
<%= line() %>
|
||||||
<button class="py-1 px-2 rounded-md text-sm hover:bg-gray-50 border border-gray-200"
|
<button class="py-1 px-2 rounded-lg text-sm hover:bg-gray-50 border border-gray-200"
|
||||||
phx-click="insert_cell"
|
phx-click="insert_cell"
|
||||||
phx-value-type="markdown"
|
phx-value-type="markdown"
|
||||||
phx-value-section_id="<%= @section_id %>"
|
phx-value-section_id="<%= @section_id %>"
|
||||||
phx-value-index="<%= @index %>">
|
phx-value-index="<%= @index %>">
|
||||||
+ Markdown
|
+ Markdown
|
||||||
</button>
|
</button>
|
||||||
<button class="py-1 px-2 rounded-md text-sm hover:bg-gray-50 border border-gray-200"
|
<button class="py-1 px-2 rounded-lg text-sm hover:bg-gray-50 border border-gray-200"
|
||||||
phx-click="insert_cell"
|
phx-click="insert_cell"
|
||||||
phx-value-type="elixir"
|
phx-value-type="elixir"
|
||||||
phx-value-section_id="<%= @section_id %>"
|
phx-value-section_id="<%= @section_id %>"
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,15 @@ defmodule LivebookWeb.ModalComponent do
|
||||||
phx-page-loading></div>
|
phx-page-loading></div>
|
||||||
|
|
||||||
<!-- Modal box -->
|
<!-- Modal box -->
|
||||||
<div class="relative max-h-full overflow-y-auto bg-white rounded-md shadow-xl"
|
<div class="relative max-h-full overflow-y-auto bg-white rounded-lg shadow-xl"
|
||||||
role="dialog"
|
role="dialog"
|
||||||
aria-modal="true">
|
aria-modal="true">
|
||||||
|
|
||||||
|
<%= live_patch to: @return_to, class: "absolute top-6 right-6 text-gray-400 flex space-x-1 items-center" do %>
|
||||||
|
<span class="text-sm">(esc)</span>
|
||||||
|
<%= remix_icon("close-line", class: "text-2xl") %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<%= live_component @socket, @component, @opts %>
|
<%= live_component @socket, @component, @opts %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ defmodule LivebookWeb.PathSelectComponent do
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~L"""
|
~L"""
|
||||||
<form phx-change="set_path" phx-submit="set_path" <%= if @target, do: "phx-target=#{@target}" %>>
|
<form phx-change="set_path" phx-submit="set_path" <%= if @target, do: "phx-target=#{@target}" %>>
|
||||||
<input class="input-base shadow"
|
<input class="input-base"
|
||||||
id="input-path"
|
id="input-path"
|
||||||
phx-hook="FocusOnUpdate"
|
phx-hook="FocusOnUpdate"
|
||||||
type="text"
|
type="text"
|
||||||
|
|
@ -37,22 +37,22 @@ defmodule LivebookWeb.PathSelectComponent do
|
||||||
defp render_file(file, target) do
|
defp render_file(file, target) do
|
||||||
icon =
|
icon =
|
||||||
case file do
|
case file do
|
||||||
%{is_running: true} -> :play
|
%{is_running: true} -> "play-circle-line"
|
||||||
%{is_dir: true} -> :folder
|
%{is_dir: true} -> "folder-fill"
|
||||||
_ -> :document_text
|
_ -> "file-code-line"
|
||||||
end
|
end
|
||||||
|
|
||||||
assigns = %{file: file, icon: icon}
|
assigns = %{file: file, icon: icon}
|
||||||
|
|
||||||
~L"""
|
~L"""
|
||||||
<button class="flex space-x-2 items-center p-2 rounded-md hover:bg-gray-100 focus:ring-1 focus:ring-blue-400 <%= if(@file.is_running, do: "text-green-400 opacity-75", else: "text-gray-700") %>"
|
<button class="flex space-x-2 items-center p-2 rounded-lg hover:bg-gray-100 focus:ring-1 focus:ring-gray-400"
|
||||||
phx-click="set_path"
|
phx-click="set_path"
|
||||||
phx-value-path="<%= file.path %>"
|
phx-value-path="<%= file.path %>"
|
||||||
<%= if target, do: "phx-target=#{target}" %>>
|
<%= if target, do: "phx-target=#{target}" %>>
|
||||||
<span class="block">
|
<span class="block">
|
||||||
<%= Icons.svg(@icon, class: "h-5") %>
|
<%= remix_icon(@icon, class: "text-xl align-middle #{if(@file.is_running, do: "text-green-300", else: "text-gray-400")}") %>
|
||||||
</span>
|
</span>
|
||||||
<span class="block overflow-hidden overflow-ellipsis whitespace-nowrap">
|
<span class="block font-medium overflow-hidden overflow-ellipsis whitespace-nowrap <%= if(@file.is_running, do: "text-green-300", else: "text-gray-500") %>">
|
||||||
<%= file.name %>
|
<%= file.name %>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ defmodule LivebookWeb.SectionComponent do
|
||||||
</div>
|
</div>
|
||||||
<div class="flex space-x-2 items-center">
|
<div class="flex space-x-2 items-center">
|
||||||
<button phx-click="delete_section" phx-value-section_id="<%= @section.id %>" class="text-gray-600 hover:text-current" tabindex="-1">
|
<button phx-click="delete_section" phx-value-section_id="<%= @section.id %>" class="text-gray-600 hover:text-current" tabindex="-1">
|
||||||
<%= Icons.svg(:trash, class: "h-6") %>
|
<%= remix_icon("delete-bin-line", class: "text-2xl") %>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -91,14 +91,14 @@ defmodule LivebookWeb.SessionLive do
|
||||||
<% end %>
|
<% end %>
|
||||||
<button phx-click="add_section" class="py-2 px-4 rounded-l-md cursor-pointer text-gray-300 hover:text-gray-400">
|
<button phx-click="add_section" class="py-2 px-4 rounded-l-md cursor-pointer text-gray-300 hover:text-gray-400">
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
<%= Icons.svg(:plus, class: "h-6") %>
|
<%= remix_icon("add-line", class: "text-2xl") %>
|
||||||
<span>New section</span>
|
<span>New section</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<%= live_patch to: Routes.session_path(@socket, :runtime, @session_id) do %>
|
<%= live_patch to: Routes.session_path(@socket, :runtime, @session_id) do %>
|
||||||
<div class="text-sm text-gray-500 text-medium px-4 py-2 border-b border-gray-200 flex space-x-2 items-center hover:bg-gray-200">
|
<div class="text-sm text-gray-500 text-medium px-4 py-2 border-b border-gray-200 flex space-x-2 items-center hover:bg-gray-200">
|
||||||
<%= Icons.svg(:chip, class: "h-5 text-gray-400") %>
|
<%= remix_icon("cpu-line", class: "text-xl text-gray-400") %>
|
||||||
<span><%= runtime_description(@data.runtime) %></span>
|
<span><%= runtime_description(@data.runtime) %></span>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
@ -106,15 +106,15 @@ defmodule LivebookWeb.SessionLive do
|
||||||
<div class="text-sm text-gray-500 text-medium px-4 py-2 border-b border-gray-200 flex space-x-2 items-center hover:bg-gray-200">
|
<div class="text-sm text-gray-500 text-medium px-4 py-2 border-b border-gray-200 flex space-x-2 items-center hover:bg-gray-200">
|
||||||
<%= if @data.path do %>
|
<%= if @data.path do %>
|
||||||
<%= if @data.dirty do %>
|
<%= if @data.dirty do %>
|
||||||
<%= Icons.svg(:dots_circle_horizontal, class: "h-5 text-blue-400") %>
|
<%= remix_icon("refresh-line", class: "text-xl text-blue-600") %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= Icons.svg(:check_circle, class: "h-5 text-green-400") %>
|
<%= remix_icon("checkbox-circle-line", class: "text-xl text-green-400") %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<span>
|
<span>
|
||||||
<%= Path.basename(@data.path) %>
|
<%= Path.basename(@data.path) %>
|
||||||
</span>
|
</span>
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= Icons.svg(:document_text, class: "h-5 text-gray-400") %>
|
<%= remix_icon("file-code-line", class: "text-xl text-gray-400") %>
|
||||||
<span>
|
<span>
|
||||||
No file choosen
|
No file choosen
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -123,10 +123,10 @@ defmodule LivebookWeb.SessionLive do
|
||||||
<% end %>
|
<% end %>
|
||||||
<div class="p-4 flex space-x-2">
|
<div class="p-4 flex space-x-2">
|
||||||
<%= live_patch to: Routes.home_path(@socket, :page) do %>
|
<%= live_patch to: Routes.home_path(@socket, :page) do %>
|
||||||
<%= Icons.svg(:home, class: "h-6 w-6 text-gray-600 hover:text-current") %>
|
<%= remix_icon("home-2-line", class: "text-2xl text-gray-600 hover:text-current") %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= live_patch to: Routes.session_path(@socket, :shortcuts, @session_id) do %>
|
<%= live_patch to: Routes.session_path(@socket, :shortcuts, @session_id) do %>
|
||||||
<%= Icons.svg(:question_mark_circle, class: "h-6 w-6 text-gray-600 hover:text-current") %>
|
<%= remix_icon("question-line", class: "text-2xl text-gray-600 hover:text-current") %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ defmodule LivebookWeb.SessionLive.AttachedLive do
|
||||||
~L"""
|
~L"""
|
||||||
<div class="flex-col space-y-3">
|
<div class="flex-col space-y-3">
|
||||||
<%= if @error_message do %>
|
<%= if @error_message do %>
|
||||||
<div class="mb-3 rounded-md px-4 py-2 bg-red-100 text-red-400 font-medium">
|
<div class="mb-3 rounded-lg px-4 py-2 bg-red-100 text-red-400 font-medium">
|
||||||
<%= @error_message %>
|
<%= @error_message %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
@ -35,10 +35,10 @@ defmodule LivebookWeb.SessionLive.AttachedLive do
|
||||||
Then enter the name of the node below:
|
Then enter the name of the node below:
|
||||||
</p>
|
</p>
|
||||||
<%= f = form_for :node, "#", phx_submit: "init" %>
|
<%= f = form_for :node, "#", phx_submit: "init" %>
|
||||||
<%= text_input f, :name, class: "input-base shadow",
|
<%= text_input f, :name, class: "input-base",
|
||||||
placeholder: if(Livebook.Config.shortnames?, do: "test", else: "test@127.0.0.1") %>
|
placeholder: if(Livebook.Config.shortnames?, do: "test", else: "test@127.0.0.1") %>
|
||||||
|
|
||||||
<%= submit "Connect", class: "mt-3 button-base button-sm" %>
|
<%= submit "Connect", class: "mt-3 button-base" %>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ defmodule LivebookWeb.SessionLive.CellSettingsComponent do
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-6 flex justify-end space-x-2">
|
<div class="mt-6 flex justify-end space-x-2">
|
||||||
<%= live_patch "Cancel", to: @return_to, class: "button-base button-sm" %>
|
<%= live_patch "Cancel", to: @return_to, class: "button-base" %>
|
||||||
<button class="button-base button-primary button-sm" type="submit">
|
<button class="button-base button-primary" type="submit">
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ defmodule LivebookWeb.SessionLive.ElixirStandaloneLive do
|
||||||
This is the default runtime and is started automatically
|
This is the default runtime and is started automatically
|
||||||
as soon as you evaluate the first cell.
|
as soon as you evaluate the first cell.
|
||||||
</p>
|
</p>
|
||||||
<button class="button-base button-sm" phx-click="init">
|
<button class="button-base" phx-click="init">
|
||||||
Connect
|
Connect
|
||||||
</button>
|
</button>
|
||||||
<%= if @output do %>
|
<%= if @output do %>
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ defmodule LivebookWeb.SessionLive.MixStandaloneLive do
|
||||||
extnames: [],
|
extnames: [],
|
||||||
running_paths: [],
|
running_paths: [],
|
||||||
target: nil %>
|
target: nil %>
|
||||||
<%= content_tag :button, "Connect", class: "button-base button-sm", phx_click: "init", disabled: not mix_project_root?(@path) %>
|
<%= content_tag :button, "Connect", class: "button-base", phx_click: "init", disabled: not mix_project_root?(@path) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= if @status != :initial do %>
|
<%= if @status != :initial do %>
|
||||||
<div class="markdown">
|
<div class="markdown">
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ defmodule LivebookWeb.SessionLive.PersistenceComponent do
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<%= content_tag :button, "Done",
|
<%= content_tag :button, "Done",
|
||||||
class: "button-base button-primary button-sm",
|
class: "button-base button-primary",
|
||||||
phx_click: "done",
|
phx_click: "done",
|
||||||
phx_target: @myself,
|
phx_target: @myself,
|
||||||
disabled: not path_savable?(normalize_path(@path), @session_summaries) %>
|
disabled: not path_savable?(normalize_path(@path), @session_summaries) %>
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ defmodule LivebookWeb.SessionLive.RuntimeComponent do
|
||||||
The code is evaluated in a separate Elixir runtime (node),
|
The code is evaluated in a separate Elixir runtime (node),
|
||||||
which you can configure yourself here.
|
which you can configure yourself here.
|
||||||
</p>
|
</p>
|
||||||
<div class="shadow rounded-md p-2">
|
<div class="border border-gray-200 rounded-lg p-2">
|
||||||
<%= if @runtime do %>
|
<%= if @runtime do %>
|
||||||
<table class="w-full text-center text-sm">
|
<table class="w-full text-center text-sm">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
@ -35,7 +35,7 @@ defmodule LivebookWeb.SessionLive.RuntimeComponent do
|
||||||
<td><%= runtime_type_label(@runtime) %></td>
|
<td><%= runtime_type_label(@runtime) %></td>
|
||||||
<td><%= @runtime.node %></td>
|
<td><%= @runtime.node %></td>
|
||||||
<td>
|
<td>
|
||||||
<button class="button-base text-sm button-sm button-danger"
|
<button class="button-base text-sm button-danger"
|
||||||
type="button"
|
type="button"
|
||||||
phx-click="disconnect"
|
phx-click="disconnect"
|
||||||
phx-target="<%= @myself %>">
|
phx-target="<%= @myself %>">
|
||||||
|
|
|
||||||
|
|
@ -3,26 +3,26 @@ defmodule LivebookWeb.SessionLive.ShortcutsComponent do
|
||||||
|
|
||||||
@shortcuts %{
|
@shortcuts %{
|
||||||
insert_mode: [
|
insert_mode: [
|
||||||
%{seq: "esc", desc: "Switch back to navigation mode"},
|
%{seq: ["esc"], desc: "Switch back to navigation mode"},
|
||||||
%{seq: "ctrl + enter", desc: "Evaluate cell and stay in insert mode"}
|
%{seq: ["ctrl", "↵"], desc: "Evaluate cell and stay in insert mode"}
|
||||||
],
|
],
|
||||||
navigation_mode: [
|
navigation_mode: [
|
||||||
%{seq: "?", desc: "Open this help modal"},
|
%{seq: ["?"], desc: "Open this help modal"},
|
||||||
%{seq: "j", desc: "Focus next cell"},
|
%{seq: ["j"], desc: "Focus next cell"},
|
||||||
%{seq: "k", desc: "Focus previous cell"},
|
%{seq: ["k"], desc: "Focus previous cell"},
|
||||||
%{seq: "J", desc: "Move cell down"},
|
%{seq: ["J"], desc: "Move cell down"},
|
||||||
%{seq: "K", desc: "Move cell up"},
|
%{seq: ["K"], desc: "Move cell up"},
|
||||||
%{seq: "i", desc: "Switch to insert mode"},
|
%{seq: ["i"], desc: "Switch to insert mode"},
|
||||||
%{seq: "n", desc: "Insert Elixir cell below"},
|
%{seq: ["n"], desc: "Insert Elixir cell below"},
|
||||||
%{seq: "m", desc: "Insert Markdown cell below"},
|
%{seq: ["m"], desc: "Insert Markdown cell below"},
|
||||||
%{seq: "N", desc: "Insert Elixir cell above"},
|
%{seq: ["N"], desc: "Insert Elixir cell above"},
|
||||||
%{seq: "M", desc: "Insert Markdown cell above"},
|
%{seq: ["M"], desc: "Insert Markdown cell above"},
|
||||||
%{seq: "dd", desc: "Delete cell"},
|
%{seq: ["dd"], desc: "Delete cell"},
|
||||||
%{seq: "ee", desc: "Evaluate cell"},
|
%{seq: ["ee"], desc: "Evaluate cell"},
|
||||||
%{seq: "es", desc: "Evaluate section"},
|
%{seq: ["es"], desc: "Evaluate section"},
|
||||||
%{seq: "ea", desc: "Evaluate all stale/new cells"},
|
%{seq: ["ea"], desc: "Evaluate all stale/new cells"},
|
||||||
%{seq: "ej", desc: "Evaluate cells below"},
|
%{seq: ["ej"], desc: "Evaluate cells below"},
|
||||||
%{seq: "ex", desc: "Cancel cell evaluation"}
|
%{seq: ["ex"], desc: "Cancel cell evaluation"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,10 +35,10 @@ defmodule LivebookWeb.SessionLive.ShortcutsComponent do
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~L"""
|
~L"""
|
||||||
<div class="p-6 sm:max-w-4xl sm:w-full flex flex-col space-y-3">
|
<div class="p-6 sm:max-w-4xl sm:w-full flex flex-col space-y-3">
|
||||||
<h3 class="text-lg font-medium text-gray-900">
|
<h3 class="text-2xl font-semibold text-gray-800">
|
||||||
Keyboard shortcuts
|
Keyboard shortcuts
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-gray-500">
|
<p class="text-gray-700">
|
||||||
Livebook highly embraces keyboard navigation to improve your productivity.
|
Livebook highly embraces keyboard navigation to improve your productivity.
|
||||||
It operates in one of two modes similarly to the Vim text editor.
|
It operates in one of two modes similarly to the Vim text editor.
|
||||||
In <span class="font-semibold">navigation mode</span> you move around
|
In <span class="font-semibold">navigation mode</span> you move around
|
||||||
|
|
@ -78,10 +78,8 @@ defmodule LivebookWeb.SessionLive.ShortcutsComponent do
|
||||||
<tbody>
|
<tbody>
|
||||||
<%= for shortcut <- @shortcuts do %>
|
<%= for shortcut <- @shortcuts do %>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="py-1 pr-4">
|
<td class="py-2 pr-3">
|
||||||
<span class="bg-editor text-editor py-0.5 px-2 rounded-md inline-flex items-center">
|
<%= render_seq(shortcut.seq, @platform) %>
|
||||||
<%= if(@platform == :mac, do: seq_for_mac(shortcut.seq), else: shortcut.seq) %>
|
|
||||||
</span>
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<%= shortcut.desc %>
|
<%= shortcut.desc %>
|
||||||
|
|
@ -93,10 +91,40 @@ defmodule LivebookWeb.SessionLive.ShortcutsComponent do
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp render_seq(seq, platform) do
|
||||||
|
seq = if(platform == :mac, do: seq_for_mac(seq), else: seq)
|
||||||
|
|
||||||
|
joiner = remix_icon("add-line", class: "text-xl text-gray-600")
|
||||||
|
|
||||||
|
elements =
|
||||||
|
seq
|
||||||
|
|> Enum.map(&render_key/1)
|
||||||
|
|> Enum.intersperse(joiner)
|
||||||
|
|
||||||
|
assigns = %{elements: elements}
|
||||||
|
|
||||||
|
~L"""
|
||||||
|
<div class="flex space-x-1 items-center">
|
||||||
|
<%= for element <- @elements do %>
|
||||||
|
<%= element %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp render_key(key) do
|
||||||
|
content_tag("span", key,
|
||||||
|
class:
|
||||||
|
"bg-editor text-gray-200 text-sm font-semibold h-8 w-8 flex items-center justify-center rounded-lg inline-flex items-center"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
defp seq_for_mac(seq) do
|
defp seq_for_mac(seq) do
|
||||||
seq
|
Enum.map(seq, fn
|
||||||
|> String.replace("ctrl", "cmd")
|
"ctrl" -> "⌘"
|
||||||
|> String.replace("alt", "option")
|
"alt" -> "⌥"
|
||||||
|
key -> key
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp split_in_half(list) do
|
defp split_in_half(list) do
|
||||||
|
|
|
||||||
|
|
@ -6,24 +6,23 @@ defmodule LivebookWeb.SessionsComponent do
|
||||||
@impl true
|
@impl true
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~L"""
|
~L"""
|
||||||
<div class="mt-3 flex flex-col space-y-2">
|
<div class="flex flex-col space-y-4">
|
||||||
<%= for summary <- @session_summaries do %>
|
<%= for summary <- @session_summaries do %>
|
||||||
<div class="shadow rounded-md p-2">
|
<div class="p-5 flex items-center border border-gray-200 rounded-lg">
|
||||||
<div class="p-3 flex items-center">
|
<div class="flex-grow flex flex-col space-y-1">
|
||||||
<div class="flex-grow flex flex-col space-y-1 text-gray-700 text-lg hover:text-gray-900">
|
<%= live_redirect summary.notebook_name, to: Routes.session_path(@socket, :page, summary.session_id),
|
||||||
<%= live_redirect summary.notebook_name, to: Routes.session_path(@socket, :page, summary.session_id) %>
|
class: "font-semibold text-gray-800 hover:text-gray-900" %>
|
||||||
<div class="text-gray-500 text-sm">
|
<div class="text-gray-600 text-sm">
|
||||||
<%= summary.path || "No file" %>
|
<%= summary.path || "No file" %>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<button class="text-gray-500 hover:text-current"
|
|
||||||
phx-click="delete_session"
|
|
||||||
phx-value-id="<%= summary.session_id %>"
|
|
||||||
phx-target="<%= @myself %>"
|
|
||||||
aria-label="delete">
|
|
||||||
<%= Icons.svg(:trash, class: "h-6") %>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<button class="text-gray-400 hover:text-current"
|
||||||
|
phx-click="delete_session"
|
||||||
|
phx-value-id="<%= summary.session_id %>"
|
||||||
|
phx-target="<%= @myself %>"
|
||||||
|
aria-label="delete">
|
||||||
|
<%= remix_icon("delete-bin-line", class: "text-xl") %>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
<main role="main" class="flex-grow flex flex-col h-screen">
|
<main role="main" class="flex-grow flex flex-col h-screen">
|
||||||
<div class="fixed right-5 bottom-5 z-50 flex flex-col space-y-3">
|
<div class="fixed right-5 bottom-5 z-50 flex flex-col space-y-3">
|
||||||
<%= if live_flash(@flash, :info) do %>
|
<%= if live_flash(@flash, :info) do %>
|
||||||
<div class="flex items-center space-x-2 rounded-md px-4 py-2 bg-blue-100 text-blue-400 hover:opacity-75 cursor-pointer" role="alert"
|
<div class="flex items-center space-x-2 rounded-lg px-4 py-2 bg-blue-100 text-blue-600 hover:opacity-75 cursor-pointer" role="alert"
|
||||||
phx-click="lv:clear-flash"
|
phx-click="lv:clear-flash"
|
||||||
phx-value-key="info">
|
phx-value-key="info">
|
||||||
<%= Icons.svg(:information_circle, class: "h-6 w-6") %>
|
<%= remix_icon("information-line", class: "text-2xl") %>
|
||||||
<span class="whitespace-pre"><%= live_flash(@flash, :info) %></span>
|
<span class="whitespace-pre"><%= live_flash(@flash, :info) %></span>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= if live_flash(@flash, :error) do %>
|
<%= if live_flash(@flash, :error) do %>
|
||||||
<div class="flex items-center space-x-2 rounded-md px-4 py-2 bg-red-100 text-red-400 hover:opacity-75 cursor-pointer" role="alert"
|
<div class="flex items-center space-x-2 rounded-lg px-4 py-2 bg-red-100 text-red-400 hover:opacity-75 cursor-pointer" role="alert"
|
||||||
phx-click="lv:clear-flash"
|
phx-click="lv:clear-flash"
|
||||||
phx-value-key="error">
|
phx-value-key="error">
|
||||||
<%= Icons.svg(:exclamation_circle, class: "h-6 w-6") %>
|
<%= remix_icon("error-warning-line", class: "text-2xl") %>
|
||||||
<span class="whitespace-pre"><%= live_flash(@flash, :error) %></span>
|
<span class="whitespace-pre"><%= live_flash(@flash, :error) %></span>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ defmodule LivebookWeb.HomeLiveTest do
|
||||||
|
|
||||||
test "disconnected and connected render", %{conn: conn} do
|
test "disconnected and connected render", %{conn: conn} do
|
||||||
{:ok, view, disconnected_html} = live(conn, "/")
|
{:ok, view, disconnected_html} = live(conn, "/")
|
||||||
assert disconnected_html =~ "Livebook"
|
assert disconnected_html =~ "Running Sessions"
|
||||||
assert render(view) =~ "Livebook"
|
assert render(view) =~ "Running Sessions"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "redirects to session upon creation", %{conn: conn} do
|
test "redirects to session upon creation", %{conn: conn} do
|
||||||
|
|
@ -16,7 +16,7 @@ defmodule LivebookWeb.HomeLiveTest do
|
||||||
|
|
||||||
assert {:error, {:live_redirect, %{to: to}}} =
|
assert {:error, {:live_redirect, %{to: to}}} =
|
||||||
view
|
view
|
||||||
|> element("button", "New notebook")
|
|> element("button", "New Notebook")
|
||||||
|> render_click()
|
|> render_click()
|
||||||
|
|
||||||
assert to =~ "/sessions/"
|
assert to =~ "/sessions/"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue