diff --git a/assets/css/js_interop.css b/assets/css/js_interop.css index bac2d88eb2f..563b0ae6a86 100644 --- a/assets/css/js_interop.css +++ b/assets/css/js_interop.css @@ -136,6 +136,30 @@ solely client-side operations. left: calc(-45vw + 50%); } +[data-el-cell]:fullscreen { + @apply bg-white m-0 px-4; + + width: 90vw; + position: relative; + overflow: scroll; +} + +[data-el-outputs-container]:fullscreen { + @apply bg-white m-0 px-4; + + width: 90vw; + position: relative; + overflow: scroll; +} + +[data-el-js-view-iframe]:fullscreen { + @apply bg-white m-0 px-4; + + width: 90vw; + position: relative; + overflow: scroll; +} + [data-el-cell][data-js-amplified] [data-el-amplify-outputs-button] > button { @apply bg-gray-100 text-gray-900; } diff --git a/assets/js/hooks/cell.js b/assets/js/hooks/cell.js index e79e46052e7..d4dd94bf1df 100644 --- a/assets/js/hooks/cell.js +++ b/assets/js/hooks/cell.js @@ -50,6 +50,39 @@ const Cell = { }); } + if (["code", "smart"].includes(this.props.type)) { + const fullscreen = (container, findIFrame) => { + if (findIFrame) { + const p_ref = container.querySelector(`[data-p-ref]`) + if (p_ref) { + const ref = p_ref.getAttribute("data-p-ref").replaceAll('"', '') + const iframe = document.querySelector(`[data-el-js-view-iframe="${ref}"]`) + if (iframe !== undefined) { + container = iframe + } + } + } + + container.requestFullscreen().catch(err => { + console.error(`Error attempting to enable fullscreen: ${err.message}`) + }) + } + const fullscreenButton = this.el.querySelector( + `[data-el-fullscreen-button]`, + ); + fullscreenButton.addEventListener("click", (event) => { + fullscreen(this.el, false) + }); + + const fullscreenOutputButton = this.el.querySelector( + `[data-el-fullscreen-output-button]`, + ); + fullscreenOutputButton.addEventListener("click", (event) => { + const cellOutputs = this.el.querySelector(`[data-el-outputs-container]`) + fullscreen(cellOutputs, true) + }); + } + if (this.props.type === "smart") { const toggleSourceButton = this.el.querySelector( `[data-el-toggle-source-button]`, diff --git a/assets/js/hooks/js_view.js b/assets/js/hooks/js_view.js index 767314d6a9f..1d4a7e68b0b 100644 --- a/assets/js/hooks/js_view.js +++ b/assets/js/hooks/js_view.js @@ -210,6 +210,7 @@ const JSView = { this.iframe = document.createElement("iframe"); this.iframe.className = "w-full h-0 absolute z-[1]"; + this.iframe.setAttribute("data-el-js-view-iframe", this.props.ref); const notebookEl = document.querySelector(`[data-el-notebook]`); const notebookContentEl = notebookEl.querySelector( diff --git a/lib/livebook_web/live/session_live/cell_component.ex b/lib/livebook_web/live/session_live/cell_component.ex index 30aead3c5f3..57581c35601 100644 --- a/lib/livebook_web/live/session_live/cell_component.ex +++ b/lib/livebook_web/live/session_live/cell_component.ex @@ -105,6 +105,7 @@ defmodule LivebookWeb.SessionLive.CellComponent do <.cell_settings_button cell_id={@cell_view.id} session_id={@session_id} /> <.amplify_output_button /> + <.fullscreen_button cell_id={@cell_view.id} /> <.cell_link_button cell_id={@cell_view.id} /> <.move_cell_up_button cell_id={@cell_view.id} /> <.move_cell_down_button cell_id={@cell_view.id} /> @@ -202,6 +203,7 @@ defmodule LivebookWeb.SessionLive.CellComponent do <.toggle_source_button /> <.convert_smart_cell_button cell_id={@cell_view.id} /> <.amplify_output_button /> + <.fullscreen_button cell_id={@cell_view.id} /> <.cell_link_button cell_id={@cell_view.id} /> <.move_cell_up_button cell_id={@cell_view.id} /> <.move_cell_down_button cell_id={@cell_view.id} /> @@ -527,6 +529,30 @@ defmodule LivebookWeb.SessionLive.CellComponent do """ end + def fullscreen_button(assigns) do + ~H""" +