Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix various layout and stylesheet bugs #77

Merged
merged 8 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion lib/live_view_native/extensions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ defmodule LiveViewNative.Extensions do
respectively.
"""
defmacro __using__(opts) do
compiled_at = :os.system_time(:nanosecond)
role = opts[:role]

quote bind_quoted: [caller: Macro.escape(__CALLER__), role: role], location: :keep do
quote bind_quoted: [caller: Macro.escape(__CALLER__), compiled_at: compiled_at, role: role],
location: :keep do
Code.put_compiler_option(:ignore_module_conflict, true)

for {platform_id, platform_context} <- LiveViewNative.platforms() do
Expand Down Expand Up @@ -43,10 +45,12 @@ defmodule LiveViewNative.Extensions do

if is_nil(platform_context.render_macro) do
use LiveViewNative.Extensions.InlineRender,
compiled_at: compiled_at,
platform_id: platform_id,
role: role
else
use LiveViewNative.Extensions.RenderMacro,
compiled_at: compiled_at,
platform_id: platform_id,
render_macro: platform_context.render_macro,
role: role
Expand Down
5 changes: 4 additions & 1 deletion lib/live_view_native/extensions/inline_render.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule LiveViewNative.Extensions.InlineRender do
@moduledoc false

Check warning on line 3 in lib/live_view_native/extensions/inline_render.ex

View workflow job for this annotation

GitHub Actions / Build and test

this clause cannot match because a previous clause at line 3 always matches

Check warning on line 3 in lib/live_view_native/extensions/inline_render.ex

View workflow job for this annotation

GitHub Actions / Build and test

this clause cannot match because a previous clause at line 3 always matches

Check warning on line 3 in lib/live_view_native/extensions/inline_render.ex

View workflow job for this annotation

GitHub Actions / Build and test

this clause cannot match because a previous clause at line 3 always matches
@doc """
This macro enables inline-rendering of templates for any LiveView Native
platform. Using this macro causes a module to inherit a `LVN/2` sigil that
Expand Down Expand Up @@ -31,10 +31,12 @@
"""
defmacro __using__(opts \\ []) do
quote bind_quoted: [
compiled_at: opts[:compiled_at],
platform_id: opts[:platform_id],
stylesheet: opts[:stylesheet],
role: opts[:role]
], location: :keep do
],
location: :keep do
require EEx

defmacro sigil_LVN({:<<>>, meta, [expr]}, modifiers) do
Expand All @@ -47,6 +49,7 @@
platform_module <- Module.concat(__ENV__.module, context.template_namespace) do
base_opts = [
caller: __CALLER__,
compiled_at: unquote(compiled_at),
engine: Phoenix.LiveView.TagEngine,
file: __CALLER__.file,
indentation: meta[:indentation] || 0,
Expand Down
3 changes: 2 additions & 1 deletion lib/live_view_native/extensions/modifiers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ defmodule LiveViewNative.Extensions.Modifiers do
modifiers_struct: opts[:modifiers_struct],
platform_modifiers: opts[:platform_modifiers],
platform_module: opts[:platform_module]
], location: :keep do
],
location: :keep do
all_modifiers = Keyword.merge(platform_modifiers, custom_modifiers)

if is_nil(platform_module) do
Expand Down
5 changes: 4 additions & 1 deletion lib/live_view_native/extensions/render_macro.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ defmodule LiveViewNative.Extensions.RenderMacro do
"""
defmacro __using__(opts \\ []) do
quote bind_quoted: [
compiled_at: opts[:compiled_at],
render_macro: opts[:render_macro],
platform_id: opts[:platform_id],
role: opts[:role]
], location: :keep do
],
location: :keep do
defmacro unquote(:"#{render_macro}")({:<<>>, meta, [expr]}, _modifiers) do
unless Macro.Env.has_var?(__CALLER__, {:assigns, nil}) do
raise "#{unquote(render_macro)} requires a variable named \"assigns\" to exist and be set to a map"
Expand All @@ -22,6 +24,7 @@ defmodule LiveViewNative.Extensions.RenderMacro do
%LiveViewNativePlatform.Env{} = context <- Map.get(platforms, unquote(platform_id)),
platform_module <- Module.concat(__ENV__.module, context.template_namespace) do
base_opts = [
compiled_at: unquote(compiled_at),
caller: __CALLER__,
engine: Phoenix.LiveView.TagEngine,
file: __CALLER__.file,
Expand Down
20 changes: 5 additions & 15 deletions lib/live_view_native/extensions/stylesheets.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,12 @@ defmodule LiveViewNative.Extensions.Stylesheets do

quote bind_quoted: [module: module], location: :keep do
def __compiled_stylesheet__(stylesheet_key) do
class_tree_module =
Module.safe_concat([LiveViewNative, Internal, ClassTree, unquote(module)])
stylesheet_modules = __stylesheet_modules__()

class_tree = apply(class_tree_module, :class_tree, [stylesheet_key])

class_names =
class_tree
|> Map.values()
|> List.flatten()

__stylesheet_modules__()
|> Enum.reduce(%{}, fn stylesheet_module, acc ->
compiled_stylesheet = apply(stylesheet_module, :compile_ast, [class_names])

Map.merge(acc, compiled_stylesheet)
end)
unquote(module)
|> LiveViewNative.Stylesheets.get_class_tree_module()
|> LiveViewNative.Stylesheets.get_class_tree(stylesheet_key)
|> LiveViewNative.Stylesheets.reduce_stylesheets(stylesheet_modules)
|> inspect(limit: :infinity, charlists: :as_list, printable_limit: :infinity)
end

Expand Down
3 changes: 2 additions & 1 deletion lib/live_view_native/extensions/templates.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ defmodule LiveViewNative.Extensions.Templates do
template_basename: opts[:template_basename],
template_directory: opts[:template_directory],
template_extension: opts[:template_extension]
], location: :keep do
],
location: :keep do
template_path = Path.join(template_directory, template_basename) <> template_extension

if is_binary(template_path) and File.exists?(template_path) do
Expand Down
74 changes: 63 additions & 11 deletions lib/live_view_native/layouts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ defmodule LiveViewNative.Layouts do
|> extract_layouts_recursive(opts)
|> List.flatten()
|> Enum.map(fn layout_params -> {layout_params.render_function, layout_params} end)
|> Enum.reject(&(format_excluded?(&1, opts)))
|> Enum.reject(&format_excluded?(&1, opts))
|> Enum.into(%{})
|> apply_default_layouts(opts)
|> generate_class_trees(opts)
Expand All @@ -26,7 +26,8 @@ defmodule LiveViewNative.Layouts do
def extract_layouts_recursive({_func, _meta, [_ | _] = nodes}, %{} = opts),
do: Enum.map(nodes, &extract_layouts_recursive(&1, opts))

def extract_layouts_recursive([do: {:__block__, [], args}], %{} = opts), do: extract_layouts_recursive(args, opts)
def extract_layouts_recursive([do: {:__block__, [], args}], %{} = opts),
do: extract_layouts_recursive(args, opts)

def extract_layouts_recursive([_ | _] = nodes, %{} = opts),
do: Enum.map(nodes, &extract_layouts_recursive(&1, opts))
Expand All @@ -49,9 +50,11 @@ defmodule LiveViewNative.Layouts do
|> String.replace(".", "_")
|> String.to_atom()

is_root_template? = "#{func_name}" == "root_#{platform.platform_id}"

%{
class_tree: %{},
template: File.read!(template_path),
template: layout_template(template_path, is_root_template?),
eex_engine: platform.eex_engine,
platform_id: platform.platform_id,
render_function: func_name,
Expand All @@ -62,6 +65,31 @@ defmodule LiveViewNative.Layouts do

def compile_layout(_platform, _template_path, _opts), do: nil

def layout_template(template_path, is_root_template?) do
template_path
|> File.read!()
|> layout_template_with_live_reload(Mix.env())
|> layout_template_with_csrf_token(is_root_template?)
end

def layout_template_with_live_reload(template, :dev) do
"""
#{template}
<iframe src="/phoenix/live_reload/frame" />
"""
end

def layout_template_with_live_reload(template, _mix_env), do: template

def layout_template_with_csrf_token(template, true) do
"""
#{template}
<csrf-token value={get_csrf_token()} />
"""
end

def layout_template_with_csrf_token(template, _is_root_template?), do: template

def matches_template?({_key, %{} = platform}, filename) do
case platform.template_extension do
nil ->
Expand All @@ -73,12 +101,15 @@ defmodule LiveViewNative.Layouts do
end

def generate_class_trees(%{} = layouts, %{} = opts) do
Enum.reduce(layouts, layouts, fn {func_name, %{template: template, platform_id: platform_id} = layout}, acc ->
Enum.reduce(layouts, layouts, fn {func_name,
%{template: template, platform_id: platform_id} = layout},
acc ->
opts = Map.put(opts, :render_function, {layout.render_function, 1})

case LiveViewNative.Templates.compile_class_tree(template, platform_id, opts) do
{:ok, %{} = class_tree} ->
Map.put(acc, func_name, %{layout | class_tree: class_tree})
updated_layout = Map.put(layout, :class_tree, class_tree)
Map.put(acc, func_name, updated_layout)

_ ->
acc
Expand All @@ -88,8 +119,8 @@ defmodule LiveViewNative.Layouts do

def persist_class_trees(%{} = layouts, opts) do
layouts
|> Enum.map(fn {func_name, %{class_tree: class_tree}} -> {func_name, class_tree} end)
|> LiveViewNative.Templates.persist_class_tree_map(opts.caller.module)
|> Enum.map(&extract_class_tree/1)
|> LiveViewNative.Templates.persist_class_tree_map(opts.caller)

layouts
end
Expand All @@ -98,7 +129,7 @@ defmodule LiveViewNative.Layouts do

defp apply_default_layouts(%{} = layouts, %{default_layouts: true, platforms: platforms} = opts) do
platforms
|> Enum.reject(&(format_excluded?(&1, opts)))
|> Enum.reject(&format_excluded?(&1, opts))
|> Enum.flat_map(fn {format, %{default_layouts: %{} = default_layouts} = platform} ->
Enum.map(default_layouts, fn {layout_name, layout_source} ->
{String.to_atom("#{layout_name}_#{format}"), {layout_source, platform}}
Expand All @@ -123,6 +154,16 @@ defmodule LiveViewNative.Layouts do

defp apply_default_layouts(%{} = layouts, _opts), do: layouts

defp extract_class_tree({func_name, layout}) do
case layout do
%{class_tree: class_tree} ->
{func_name, class_tree}

_ ->
{func_name, %{}}
end
end

defp format_excluded?({_, %{platform_id: platform_id}}, %{} = opts) do
case opts do
%{exclude: [_ | _] = excluded_formats} ->
Expand All @@ -134,7 +175,10 @@ defmodule LiveViewNative.Layouts do
end

defmacro __using__(_opts \\ []) do
quote bind_quoted: [caller: Macro.escape(__CALLER__)], location: :keep do
compiled_at = :os.system_time(:nanosecond)

quote bind_quoted: [caller: Macro.escape(__CALLER__), compiled_at: compiled_at],
location: :keep do
use LiveViewNative.Extensions, role: :layouts

layout_templates =
Expand All @@ -154,15 +198,23 @@ defmodule LiveViewNative.Layouts do

eex_opts = [
caller: caller,
compiled_at: compiled_at,
engine: layout_params.eex_engine,
file: __ENV__.file,
render_function: {render_func, 1},
source: layout_params.template,
persist_class_tree: false,
tag_handler: layout_params.tag_handler
]
LiveViewNative.Templates.compile_class_tree(layout_params.template, layout_params.platform_id, eex_opts)
expr = LiveViewNative.Templates.with_stylesheet_wrapper(layout_params.template, render_func)

LiveViewNative.Templates.compile_class_tree(
layout_params.template,
layout_params.platform_id,
eex_opts
)

expr =
LiveViewNative.Templates.with_stylesheet_wrapper(layout_params.template, render_func)

EEx.function_from_string(:def, render_func, expr, [:assigns], eex_opts)
end)
Expand Down
12 changes: 8 additions & 4 deletions lib/live_view_native/live_session.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ defmodule LiveViewNative.LiveSession do
case get_native_assigns(socket, params) do
%Assigns{} = native_assigns ->
assigns = Map.from_struct(native_assigns)

socket =
socket
|> assign(assigns)
Expand Down Expand Up @@ -79,10 +80,13 @@ defmodule LiveViewNative.LiveSession do
defp put_target(assigns, _lvn_params), do: assigns

defp put_native_layout(%Socket{} = socket) do
with %Socket{assigns: %{format: format}, private: private, view: view} when not is_nil(view) <- socket,
%{layout: {layout_mod, layout_name}} <- apply(view, :__live__, [])
do
%Socket{socket | private: Map.put(private, :live_layout, {layout_mod, "#{layout_name}_#{format}"})}
with %Socket{assigns: %{format: format}, private: private, view: view} when not is_nil(view) <-
socket,
%{layout: {layout_mod, layout_name}} <- apply(view, :__live__, []) do
%Socket{
socket
| private: Map.put(private, :live_layout, {layout_mod, "#{layout_name}_#{format}"})
}
else
_ ->
socket
Expand Down
20 changes: 11 additions & 9 deletions lib/live_view_native/session_plug.ex
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
defmodule LiveViewNative.SessionPlug do
def init(default), do: default

def call(%Plug.Conn{
params: %{"_lvn" => %{"format" => lvn_platform}},
private:
%{
:phoenix_format => "html",
:phoenix_root_layout => %{"html" => {root_layout_mod, root_layout_func}}
}
} = conn, _default) do
def call(
%Plug.Conn{
params: %{"_lvn" => %{"format" => lvn_platform}},
private: %{
:phoenix_format => "html",
:phoenix_root_layout => %{"html" => {root_layout_mod, root_layout_func}}
}
} = conn,
_default
) do
root_layout_func = String.to_existing_atom("#{root_layout_func}_#{lvn_platform}")
root_layout = {root_layout_mod, root_layout_func}

Expand All @@ -18,4 +20,4 @@ defmodule LiveViewNative.SessionPlug do
end

def call(conn, _default), do: conn
end
end
Loading
Loading