-
-
Save slashdotdash/9f58728474579ccba64945ed07b69892 to your computer and use it in GitHub Desktop.
Responsive Phoenix LiveView
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const Hooks = { ViewportResizeHooks} | |
const connectLiveSocket = () => { | |
const csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute('content') | |
const liveSocket = new LiveSocket('/my_app/live', Socket, { | |
params: { | |
_csrf_token: csrfToken, | |
viewport: { | |
width: window.innerWidth, | |
height: window.innerHeight | |
} | |
}, | |
hooks: Hooks | |
}) | |
liveSocket.connect() | |
return liveSocket | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyApp.SomeLiveView.Show do | |
use MyApp, :live_view | |
use ViewportHelpers | |
def render(assigns) do | |
render_for_device(SomeView, "show.html", assigns) | |
end | |
def mount(params, session, socket) do | |
{:ok, | |
socket | |
|> assign_device_kind() | |
} | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule ViewportHelpers do | |
alias Phoenix.{LiveView, View} | |
# in sync with css/shared/_media_queries.scss | |
@mobile_max_width 480 | |
@desktop_kind :desktop | |
@mobile_kind :mobile | |
defmacro __using__(_) do | |
quote do | |
import ViewportHelpers | |
def handle_event("viewport_resize", viewport, socket) do | |
device_kind = viewport |> Map.get("width") |> device_kind_for_width() | |
{:noreply, LiveView.assign(socket, device_kind: device_kind)} | |
end | |
end | |
end | |
def assign_device_kind(socket) do | |
device_kind = | |
socket.private | |
|> get_in([:connect_params, "viewport", "width"]) | |
|> device_kind_for_width() | |
LiveView.assign(socket, device_kind: device_kind) | |
end | |
def render_for_device(module, template, assigns = %{device_kind: device_kind}) do | |
template = String.replace(template, ".html", ".#{device_kind}.html") | |
View.render(module, template, assigns) | |
end | |
def render_for_device(module, template, assigns) do | |
View.render(module, template, assigns) | |
end | |
def device_kind_for_width(width) when is_integer(width) and width <= @mobile_max_width do | |
@mobile_kind | |
end | |
def device_kind_for_width(_width), do: @desktop_kind | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import _ from 'lodash' | |
let resizeHandler | |
export const ViewportResizeHooks = { | |
mounted () { | |
// Direct push of current window size to properly update view | |
this.pushResizeEvent() | |
resizeHandler = _.debounce(() => { | |
this.pushResizeEvent() | |
}, 100) | |
window.addEventListener('resize', resizeHandler) | |
}, | |
pushResizeEvent () { | |
this.pushEvent('viewport_resize', { | |
width: window.innerWidth, | |
height: window.innerHeight | |
}) | |
}, | |
turbolinksDisconnected () { | |
window.removeEventListener('resize', resizeHandler) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment