From 832c33d61df3ad71c192858f9558859e17e6006e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20K=C5=82osko?= Date: Fri, 6 Dec 2024 10:38:58 +0100 Subject: [PATCH] Add custom view option to hide code (#2889) --- assets/css/js_interop.css | 93 ++++++++ assets/js/hooks/custom_view_settings.js | 7 + assets/js/hooks/session.js | 5 + assets/js/lib/settings.js | 1 + .../live/session_live/cell_component.ex | 204 +++++++++--------- .../session_live/custom_view_component.ex | 1 + 6 files changed, 209 insertions(+), 102 deletions(-) diff --git a/assets/css/js_interop.css b/assets/css/js_interop.css index bac2d88eb2f..ca2eb833cff 100644 --- a/assets/css/js_interop.css +++ b/assets/css/js_interop.css @@ -151,6 +151,16 @@ solely client-side operations. @apply hidden; } +[data-el-cell][data-type="smart"]:not([data-js-source-visible]) + [data-el-cell-indicators] { + @apply static flex justify-end pt-2; +} + +[data-el-cell][data-type="smart"]:not([data-js-source-visible]) + [data-el-cell-indicator] { + @apply bg-gray-50 border-gray-200 text-gray-500; +} + [data-el-session] [data-el-cell][data-type="setup"]:not( [data-eval-validity="fresh"]:not([data-js-empty]) @@ -159,6 +169,14 @@ solely client-side operations. @apply h-0 overflow-hidden; } +[data-el-session] + [data-el-cell][data-type="setup"]:not( + [data-eval-validity="fresh"]:not([data-js-empty]) + ):not([data-eval-errored]):not([data-js-changed]):not([data-js-focused]) + [data-el-cell-indicator] { + @apply bg-gray-50 border-gray-200 text-gray-500; +} + [data-el-session] [data-el-cell][data-type="setup"][data-js-focused] [data-el-info-box], @@ -341,6 +359,81 @@ solely client-side operations. @apply hidden; } +[data-js-hide-code][data-el-session]:not([data-js-insert-mode]) + [data-el-cell] + [data-el-cell-indicator], +[data-js-hide-code][data-el-session] + [data-el-cell]:not([data-js-focused]) + [data-el-cell-indicator] { + @apply bg-gray-50 border-gray-200 text-gray-500; +} + +[data-js-hide-code][data-el-session]:not([data-js-insert-mode]) + [data-el-cell][data-type="code"] + [data-el-editor-box], +[data-js-hide-code][data-el-session][data-js-insert-mode] + [data-el-cell][data-type="code"]:not([data-js-focused]) + [data-el-editor-box] { + @apply hidden; +} + +[data-js-hide-code][data-el-session] + [data-el-cell][data-type="setup"] + [data-el-info-box], +[data-js-hide-code][data-el-session]:not([data-js-insert-mode]) + [data-el-cell][data-type="setup"] + [data-el-editor-box], +[data-js-hide-code][data-el-session][data-js-insert-mode] + [data-el-cell][data-type="setup"]:not([data-js-focused]) + [data-el-editor-box] { + @apply hidden; +} + +[data-js-hide-code] [data-el-cell][data-type="smart"] [data-el-ui-box] { + @apply hidden; +} + +[data-js-hide-code][data-el-session]:not([data-js-insert-mode]) + [data-el-cell][data-type="smart"] + [data-el-editor-box], +[data-js-hide-code][data-el-session][data-js-insert-mode] + [data-el-cell][data-type="smart"]:not([data-js-focused]) + [data-el-editor-box] { + @apply hidden; +} + +[data-js-hide-code][data-el-session]:not([data-js-insert-mode]) + [data-el-cell][data-type="code"] + [data-el-cell-body-root]:after, +[data-js-hide-code][data-el-session][data-js-insert-mode] + [data-el-cell][data-type="code"]:not([data-js-focused]) + [data-el-cell-body-root]:after, +[data-js-hide-code][data-el-session]:not([data-js-insert-mode]) + [data-el-cell][data-type="setup"] + [data-el-cell-body-root]:after, +[data-js-hide-code][data-el-session][data-js-insert-mode] + [data-el-cell][data-type="setup"]:not([data-js-focused]) + [data-el-cell-body-root]:after, +[data-js-hide-code][data-el-session]:not([data-js-insert-mode]) + [data-el-cell][data-type="smart"] + [data-el-cell-body-root]:after, +[data-js-hide-code][data-el-session][data-js-insert-mode] + [data-el-cell][data-type="smart"]:not([data-js-focused]) + [data-el-cell-body-root]:after { + content: "Code"; + + @apply flex py-2 px-3 border border-gray-200 rounded-lg text-sm text-gray-400 font-medium; +} + +[data-js-hide-code][data-el-session]:not([data-js-insert-mode]) + [data-el-cell][data-type="smart"] + [data-el-cell-indicators], +[data-js-hide-code][data-el-session][data-js-insert-mode] + [data-el-cell][data-type="smart"]:not([data-js-focused]) + [data-el-cell-indicators] { + @apply absolute bottom-2 right-2; +} + [data-js-spotlight] :is( [data-el-section-headline]:not([data-js-focused]), diff --git a/assets/js/hooks/custom_view_settings.js b/assets/js/hooks/custom_view_settings.js index d4131acc075..3a1fbcb3c49 100644 --- a/assets/js/hooks/custom_view_settings.js +++ b/assets/js/hooks/custom_view_settings.js @@ -13,6 +13,9 @@ const CustomViewSettings = { const customMarkdownCheckbox = this.el.querySelector( `[name="show_markdown"][value="true"]`, ); + const customCodeCheckbox = this.el.querySelector( + `[name="show_code"][value="true"]`, + ); const customOutputCheckbox = this.el.querySelector( `[name="show_output"][value="true"]`, ); @@ -22,6 +25,7 @@ const CustomViewSettings = { customSectionCheckbox.checked = settings.custom_view_show_section; customMarkdownCheckbox.checked = settings.custom_view_show_markdown; + customCodeCheckbox.checked = settings.custom_view_show_code; customOutputCheckbox.checked = settings.custom_view_show_output; customSpotlightCheckbox.checked = settings.custom_view_spotlight; @@ -31,6 +35,9 @@ const CustomViewSettings = { customMarkdownCheckbox.addEventListener("change", (event) => { settingsStore.update({ custom_view_show_markdown: event.target.checked }); }); + customCodeCheckbox.addEventListener("change", (event) => { + settingsStore.update({ custom_view_show_code: event.target.checked }); + }); customOutputCheckbox.addEventListener("change", (event) => { settingsStore.update({ custom_view_show_output: event.target.checked }); }); diff --git a/assets/js/hooks/session.js b/assets/js/hooks/session.js index 3b01cb605e1..6d03663294a 100644 --- a/assets/js/hooks/session.js +++ b/assets/js/hooks/session.js @@ -1131,6 +1131,7 @@ const Session = { this.setView(view, { showSection: false, showMarkdown: false, + showCode: true, showOutput: true, spotlight: false, }); @@ -1138,6 +1139,7 @@ const Session = { this.setView(view, { showSection: true, showMarkdown: true, + showCode: true, showOutput: true, spotlight: true, }); @@ -1147,6 +1149,7 @@ const Session = { this.setView(view, { showSection: settings.custom_view_show_section, showMarkdown: settings.custom_view_show_markdown, + showCode: settings.custom_view_show_code, showOutput: settings.custom_view_show_output, spotlight: settings.custom_view_spotlight, }); @@ -1180,6 +1183,7 @@ const Session = { this.el.toggleAttribute("data-js-hide-section", !options.showSection); this.el.toggleAttribute("data-js-hide-markdown", !options.showMarkdown); + this.el.toggleAttribute("data-js-hide-code", !options.showCode); this.el.toggleAttribute("data-js-hide-output", !options.showOutput); this.el.toggleAttribute("data-js-spotlight", options.spotlight); }, @@ -1192,6 +1196,7 @@ const Session = { this.el.removeAttribute("data-js-hide-section"); this.el.removeAttribute("data-js-hide-markdown"); + this.el.removeAttribute("data-js-hide-code"); this.el.removeAttribute("data-js-hide-output"); this.el.removeAttribute("data-js-spotlight"); }, diff --git a/assets/js/lib/settings.js b/assets/js/lib/settings.js index 2fc35e3d810..4ec9e7c0c2b 100644 --- a/assets/js/lib/settings.js +++ b/assets/js/lib/settings.js @@ -30,6 +30,7 @@ const DEFAULTSETTINGS = { editor_mode: EDITOR_MODE.default, custom_view_show_section: true, custom_view_show_markdown: true, + custom_view_show_code: true, custom_view_show_output: true, custom_view_spotlight: false, }; diff --git a/lib/livebook_web/live/session_live/cell_component.ex b/lib/livebook_web/live/session_live/cell_component.ex index 839deea8dd5..0f9948ac7ab 100644 --- a/lib/livebook_web/live/session_live/cell_component.ex +++ b/lib/livebook_web/live/session_live/cell_component.ex @@ -109,16 +109,18 @@ defmodule LivebookWeb.SessionLive.CellComponent do <.cell_body> -
- <.cell_editor - cell_id={@cell_view.id} - tag="primary" - empty={@cell_view.empty} - language={@cell_view.language} - intellisense - /> -
- <.cell_indicators id={@cell_view.id} variant="editor" cell_view={@cell_view} /> +
+
+ <.cell_editor + cell_id={@cell_view.id} + tag="primary" + empty={@cell_view.empty} + language={@cell_view.language} + intellisense + /> +
+
+ <.cell_indicators id={@cell_view.id} cell_view={@cell_view} />
<.doctest_summary cell_id={@cell_view.id} doctest_summary={@cell_view.eval.doctest_summary} /> @@ -151,14 +153,13 @@ defmodule LivebookWeb.SessionLive.CellComponent do <.cell_body> -
-
- Notebook dependencies and setup - <.cell_indicators id={"#{@cell_view.id}-1"} variant="default" cell_view={@cell_view} /> +
+
+
+ Notebook dependencies and setup +
-
-
-
+
<.cell_editor cell_id={@cell_view.id} tag="primary" @@ -166,18 +167,18 @@ defmodule LivebookWeb.SessionLive.CellComponent do language="elixir" intellisense /> -
- <.cell_indicators id={"#{@cell_view.id}-2"} variant="editor" cell_view={@cell_view} /> -
- <.evaluation_outputs - outputs={@streams.outputs} - cell_view={@cell_view} - session_id={@session_id} - session_pid={@session_pid} - client_id={@client_id} - /> +
+ <.cell_indicators id={@cell_view.id} cell_view={@cell_view} /> +
+ <.evaluation_outputs + outputs={@streams.outputs} + cell_view={@cell_view} + session_id={@session_id} + session_pid={@session_pid} + client_id={@client_id} + /> """ end @@ -206,74 +207,72 @@ defmodule LivebookWeb.SessionLive.CellComponent do <.cell_body> -
- <%= case @cell_view.status do %> - <% :started -> %> -
+
+ <%= case @cell_view.status do %> + <% :started -> %> +
- <.live_component - module={LivebookWeb.JSViewComponent} - id={@cell_view.id} - js_view={@cell_view.js_view} - session_id={@session_id} - client_id={@client_id} - /> - <.cell_editor - :if={@cell_view.editor} - cell_id={@cell_view.id} - tag="secondary" - empty={@cell_view.editor.empty} - language={@cell_view.editor.language} - rounded={@cell_view.editor.placement} - intellisense={@cell_view.editor.language == "elixir"} - hidden={not @cell_view.editor.visible} - /> -
- <% :dead -> %> -
- <%= if @installing? do %> - Waiting for dependency installation to complete... - <% else %> - Run the notebook setup to show the contents of this Smart cell. - <% end %> -
- <% :down -> %> -
- - The Smart cell crashed unexpectedly, this is most likely a bug. - - <.button - color="gray" - phx-click={JS.push("recover_smart_cell", value: %{cell_id: @cell_view.id})} - > - Restart Smart cell - -
- <% :starting -> %> -
- <.content_skeleton empty={false} /> -
- <% end %> -
-
- <.cell_indicators id={"#{@cell_view.id}-1"} variant="default" cell_view={@cell_view} /> + <.live_component + module={LivebookWeb.JSViewComponent} + id={@cell_view.id} + js_view={@cell_view.js_view} + session_id={@session_id} + client_id={@client_id} + /> + <.cell_editor + :if={@cell_view.editor} + cell_id={@cell_view.id} + tag="secondary" + empty={@cell_view.editor.empty} + language={@cell_view.editor.language} + rounded={@cell_view.editor.placement} + intellisense={@cell_view.editor.language == "elixir"} + hidden={not @cell_view.editor.visible} + /> +
+ <% :dead -> %> +
+ <%= if @installing? do %> + Waiting for dependency installation to complete... + <% else %> + Run the notebook setup to show the contents of this Smart cell. + <% end %> +
+ <% :down -> %> +
+ + The Smart cell crashed unexpectedly, this is most likely a bug. + + <.button + color="gray" + phx-click={JS.push("recover_smart_cell", value: %{cell_id: @cell_view.id})} + > + Restart Smart cell + +
+ <% :starting -> %> +
+ <.content_skeleton empty={false} /> +
+ <% end %>
-
-
-
- <.cell_editor - cell_id={@cell_view.id} - tag="primary" - empty={@cell_view.empty} - language="elixir" - intellisense - read_only - /> -
- <.cell_indicators id={"#{@cell_view.id}-2"} variant="editor" cell_view={@cell_view} /> +
+
+ <.cell_editor + cell_id={@cell_view.id} + tag="primary" + empty={@cell_view.empty} + language="elixir" + intellisense + read_only + />
+
+ <.cell_indicators id={@cell_view.id} cell_view={@cell_view} /> +
<.evaluation_outputs outputs={@streams.outputs} @@ -683,24 +682,25 @@ defmodule LivebookWeb.SessionLive.CellComponent do defp cell_indicators(assigns) do ~H"""
-
+ <.cell_indicator :if={has_status?(@cell_view)}> <.cell_status id={@id} cell_view={@cell_view} /> -
-
+ + <.cell_indicator> <.language_icon language={cell_language(@cell_view)} class="w-3 h-3" /> -
+
""" end - defp cell_indicator_container_class(variant) do - [ - "px-1.5 h-[22px] rounded-lg flex items-center", - case variant do - "default" -> "bg-gray-50 border border-gray-200 text-gray-500 px-1.5 h-[22px]" - "editor" -> "bg-editor-lighter border border-editor text-editor px-1.5 h-[22px]" - end - ] + defp cell_indicator(assigns) do + ~H""" +
+ {render_slot(@inner_block)} +
+ """ end defp cell_language(%{language: language}), do: Atom.to_string(language) diff --git a/lib/livebook_web/live/session_live/custom_view_component.ex b/lib/livebook_web/live/session_live/custom_view_component.ex index 24b23770eeb..d675f9b40c5 100644 --- a/lib/livebook_web/live/session_live/custom_view_component.ex +++ b/lib/livebook_web/live/session_live/custom_view_component.ex @@ -23,6 +23,7 @@ defmodule LivebookWeb.SessionLive.CustomViewComponent do > <.switch_field name="show_section" label="Show sections" value={false} /> <.switch_field name="show_markdown" label="Show markdown" value={false} /> + <.switch_field name="show_code" label="Show code" value={false} /> <.switch_field name="show_output" label="Show outputs" value={false} /> <.switch_field name="spotlight" label="Spotlight focused" value={false} />