diff --git a/.formatter.exs b/.formatter.exs
index 4761678..50d7a54 100644
--- a/.formatter.exs
+++ b/.formatter.exs
@@ -1,4 +1,5 @@
[
- import_deps: [:phoenix],
- inputs: ["*.{ex,exs}", "{config,lib,test}/**/*.{ex,exs}"]
+ import_deps: [:phoenix, :surface],
+ inputs: ["*.{ex,exs}", "{config,lib,test}/**/*.{ex,exs}"],
+ surface_inputs: ["{lib,test}/**/*.{ex,exs,sface}"]
]
diff --git a/config/dev.exs b/config/dev.exs
index eec1ee8..83e21e0 100644
--- a/config/dev.exs
+++ b/config/dev.exs
@@ -51,7 +51,8 @@ config :elixir_console, ElixirConsoleWeb.Endpoint,
patterns: [
~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$",
~r"lib/elixir_console_web/(live|views)/.*(ex)$",
- ~r"lib/elixir_console_web/templates/.*(eex)$"
+ ~r"lib/elixir_console_web/templates/.*(eex)$",
+ ~r"lib/elixir_console_web/live/.*(sface)$"
]
]
diff --git a/lib/elixir_console_web/live/console_live.ex b/lib/elixir_console_web/live/console_live.ex
index 6ef5f20..6125c72 100644
--- a/lib/elixir_console_web/live/console_live.ex
+++ b/lib/elixir_console_web/live/console_live.ex
@@ -36,6 +36,28 @@ defmodule ElixirConsoleWeb.ConsoleLive do
Sandbox.terminate(sandbox)
end
+ @impl true
+ def render(assigns) do
+ ~H"""
+
+
+
+
+
+
+ <%= live_component(HistoryComponent, output: @output, id: :history) %>
+ <%= live_component(CommandInputComponent, history: @history, bindings: @sandbox.bindings, id: :command_input) %>
+
+
+
+
+ <%= live_component(SidebarComponent,
+ sandbox: @sandbox, contextual_help: @contextual_help, suggestions: @suggestions)
+ %>
+
+ """
+ end
+
# This event comes from HistoryComponent
@impl true
def handle_info({:show_function_docs, contextual_help}, socket) do
diff --git a/lib/elixir_console_web/live/console_live.html.heex b/lib/elixir_console_web/live/console_live.html.heex
deleted file mode 100644
index a74f11c..0000000
--- a/lib/elixir_console_web/live/console_live.html.heex
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
- <%= live_component(HistoryComponent, output: @output, id: :history) %>
- <%= live_component(CommandInputComponent, history: @history, bindings: @sandbox.bindings, id: :command_input) %>
-
-
-
-
- <%= live_component(SidebarComponent,
- sandbox: @sandbox, contextual_help: @contextual_help, suggestions: @suggestions)
- %>
-
diff --git a/lib/elixir_console_web/live/console_live/bindings.ex b/lib/elixir_console_web/live/console_live/bindings.ex
new file mode 100644
index 0000000..4f21907
--- /dev/null
+++ b/lib/elixir_console_web/live/console_live/bindings.ex
@@ -0,0 +1,21 @@
+defmodule ElixirConsoleWeb.ConsoleLive.Bindings do
+ use Surface.Component
+
+ @doc "Keyword list of bindings"
+ prop bindings, :keyword
+
+ def render(assigns) do
+ ~F"""
+
+ """
+ end
+end
diff --git a/lib/elixir_console_web/live/console_live/command_input_component.ex b/lib/elixir_console_web/live/console_live/command_input_component.ex
index 1284905..d7378f6 100644
--- a/lib/elixir_console_web/live/console_live/command_input_component.ex
+++ b/lib/elixir_console_web/live/console_live/command_input_component.ex
@@ -5,10 +5,13 @@ defmodule ElixirConsoleWeb.ConsoleLive.CommandInputComponent do
user experience.
"""
- use Phoenix.LiveComponent
+ use Surface.Component
import ElixirConsoleWeb.ConsoleLive.Helpers
alias ElixirConsole.Autocomplete
+ prop input_value, :string
+ prop caret_position, :integer
+
def mount(socket) do
{:ok,
assign(
@@ -19,6 +22,27 @@ defmodule ElixirConsoleWeb.ConsoleLive.CommandInputComponent do
)}
end
+ def render(assigns) do
+ ~F"""
+
+ """
+ end
+
defp ensure_number(value) when is_number(value),
do: value
diff --git a/lib/elixir_console_web/live/console_live/command_input_component.html.heex b/lib/elixir_console_web/live/console_live/command_input_component.html.heex
deleted file mode 100644
index 2e4e54a..0000000
--- a/lib/elixir_console_web/live/console_live/command_input_component.html.heex
+++ /dev/null
@@ -1,16 +0,0 @@
-
diff --git a/lib/elixir_console_web/live/console_live/contextual_help.ex b/lib/elixir_console_web/live/console_live/contextual_help.ex
new file mode 100644
index 0000000..b2421dc
--- /dev/null
+++ b/lib/elixir_console_web/live/console_live/contextual_help.ex
@@ -0,0 +1,27 @@
+defmodule ElixirConsoleWeb.ConsoleLive.ContextualHelp do
+ use Surface.Component
+
+ @doc "Link to documentation in hexdocs.pm"
+ prop link, :string
+
+ @doc "Name of the function"
+ prop func_name, :string
+
+ @doc "Header of the documentation"
+ prop header, :string
+
+ @doc "Body of the documentation"
+ prop doc, :string
+
+ def render(assigns) do
+ ~F"""
+
+ """
+ end
+end
diff --git a/lib/elixir_console_web/live/console_live/history_component.ex b/lib/elixir_console_web/live/console_live/history_component.ex
index 8e1205f..ba7c1cb 100644
--- a/lib/elixir_console_web/live/console_live/history_component.ex
+++ b/lib/elixir_console_web/live/console_live/history_component.ex
@@ -4,11 +4,38 @@ defmodule ElixirConsoleWeb.ConsoleLive.HistoryComponent do
commands and results are displayed.
"""
- use Phoenix.LiveComponent
+ use Surface.LiveComponent
import Phoenix.HTML, only: [sigil_e: 2]
import ElixirConsoleWeb.ConsoleLive.Helpers
alias ElixirConsole.ContextualHelp
+ prop output, :keyword
+
+ @impl true
+ def render(assigns) do
+ ~F"""
+
+
+
Elixir {System.version()}/OTP {System.otp_release()}
+
+ {#for output <- @output}
+
+ {print_prompt()}{format_command(output.command)}
+
+
+ {output.result}
+ {#if output.error}
+
+ {output.error}
+
+ {/if}
+
+ {/for}
+
+ """
+ end
+
+ @impl true
def handle_event(
"function_link_clicked",
%{"func_name" => func_name, "header" => header, "doc" => doc, "link" => link},
diff --git a/lib/elixir_console_web/live/console_live/history_component.html.heex b/lib/elixir_console_web/live/console_live/history_component.html.heex
deleted file mode 100644
index cdf668a..0000000
--- a/lib/elixir_console_web/live/console_live/history_component.html.heex
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
Elixir <%= System.version() %>/OTP <%= System.otp_release() %>
-
- <%= for output <- @output do %>
-
- <%= print_prompt() %><%= format_command(output.command) %>
-
-
- <%= output.result %>
- <%= if output.error do %>
-
- <%= output.error %>
-
- <% end %>
-
- <% end %>
-
diff --git a/lib/elixir_console_web/live/console_live/instructions.ex b/lib/elixir_console_web/live/console_live/instructions.ex
new file mode 100644
index 0000000..4818fbe
--- /dev/null
+++ b/lib/elixir_console_web/live/console_live/instructions.ex
@@ -0,0 +1,19 @@
+defmodule ElixirConsoleWeb.ConsoleLive.Instructions do
+ use Surface.Component
+
+ def render(assigns) do
+ ~F"""
+ INSTRUCTIONS
+ [UP] [DOWN]: Navigate through commands history
+ [TAB]: Get suggestions or autocomplete while typing
+ You can see the history panel that includes all your commands and their output.
+ Click on any Elixir function to see here the corresponding documentation.
+ ABOUT SECURITY
+ Please note some features of the language are not safe to run in a shared environment like this console.
+ If you are interested in knowing more about the limitations, you must read here.
+ Please report any security vulnerabilities to
+ elixir-console-security@wyeworks.com.
+
+ """
+ end
+end
diff --git a/lib/elixir_console_web/live/console_live/sidebar_component.ex b/lib/elixir_console_web/live/console_live/sidebar_component.ex
index 3887016..b572b48 100644
--- a/lib/elixir_console_web/live/console_live/sidebar_component.ex
+++ b/lib/elixir_console_web/live/console_live/sidebar_component.ex
@@ -5,5 +5,30 @@ defmodule ElixirConsoleWeb.ConsoleLive.SidebarComponent do
information.
"""
- use Phoenix.LiveComponent
+ use Surface.Component
+
+ alias ElixirConsoleWeb.ConsoleLive.{Bindings, Suggestions, ContextualHelp, Instructions}
+
+ prop sandbox, :map
+
+ prop suggestions, :list
+
+ prop contextual_help, :map
+
+ def render(assigns) do
+ ~F"""
+
+
+
+ {#if @suggestions != []}
+
+ {#elseif @contextual_help}
+
+ {#else}
+
+ {/if}
+
+
+ """
+ end
end
diff --git a/lib/elixir_console_web/live/console_live/sidebar_component.html.heex b/lib/elixir_console_web/live/console_live/sidebar_component.html.heex
deleted file mode 100644
index fbe80a7..0000000
--- a/lib/elixir_console_web/live/console_live/sidebar_component.html.heex
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
- <%= if @suggestions != [] do %>
-
Suggestions:
- <% else %>
- <%= if @contextual_help do %>
-
- <% else %>
-
INSTRUCTIONS
-
[UP] [DOWN]: Navigate through commands history
-
[TAB]: Get suggestions or autocomplete while typing
-
You can see the history panel that includes all your commands and their output.
- Click on any Elixir function to see here the corresponding documentation.
-
ABOUT SECURITY
-
Please note some features of the language are not safe to run in a shared environment like this console.
- If you are interested in knowing more about the limitations, you must read here.
-
Please report any security vulnerabilities to
- elixir-console-security@wyeworks.com.
-
- <% end %>
- <% end %>
-
- <%= for suggestion <- @suggestions do %>
- - <%= suggestion %>
- <% end %>
-
-
-
diff --git a/lib/elixir_console_web/live/console_live/suggestions.ex b/lib/elixir_console_web/live/console_live/suggestions.ex
new file mode 100644
index 0000000..8b289f2
--- /dev/null
+++ b/lib/elixir_console_web/live/console_live/suggestions.ex
@@ -0,0 +1,17 @@
+defmodule ElixirConsoleWeb.ConsoleLive.Suggestions do
+ use Surface.Component
+
+ @doc "List of suggestions"
+ prop suggestions, :list
+
+ def render(assigns) do
+ ~F"""
+ Suggestions:
+
+ {#for suggestion <- @suggestions}
+ - {suggestion}
+ {/for}
+
+ """
+ end
+end
diff --git a/mix.exs b/mix.exs
index 7927512..d0d5f97 100644
--- a/mix.exs
+++ b/mix.exs
@@ -41,6 +41,7 @@ defmodule ElixirConsole.MixProject do
{:earmark, "~> 1.4.0"},
{:floki, "~> 0.31.0", only: :test},
{:sentry, "~> 7.0"},
+ {:surface, "~> 0.5.2"},
{:wallaby, "~> 0.28", only: :test, runtime: false}
]
end
diff --git a/mix.lock b/mix.lock
index e8f43f1..635493d 100644
--- a/mix.lock
+++ b/mix.lock
@@ -28,6 +28,7 @@
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"sentry": {:hex, :sentry, "7.2.1", "ea6a5d26c4afef97bf21e09612ebe8d97b525b7822429092926377cd82c08f9e", [:mix], [{:hackney, "~> 1.8 or 1.6.5", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.3", [hex: :phoenix, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "8d1a9469095a83ff8575d16dc1b4d73f5444f3da1ded89a44ce8b85481180089"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
+ "surface": {:hex, :surface, "0.5.2", "905e90a348eb788732adc474d88cce5627f8a202227492498b296d230b5f4f9c", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.15", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "c98562ee29323a906b2715059fbaf9bd566674fce19dd0ca71e2a51c457a80dd"},
"telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"},
"tesla": {:hex, :tesla, "1.4.3", "f5a494e08fb1abe4fd9c28abb17f3d9b62b8f6fc492860baa91efb1aab61c8a0", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.3", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "e0755bb664bf4d664af72931f320c97adbf89da4586670f4864bf259b5750386"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},