Skip to content

Instantly share code, notes, and snippets.

@codeanpeace
Forked from cblavier/app.js
Created December 7, 2022 22:29

Revisions

  1. @cblavier cblavier created this gist Jan 9, 2021.
    17 changes: 17 additions & 0 deletions app.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,17 @@
    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
    }
    15 changes: 15 additions & 0 deletions some_liveview.ex
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    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
    44 changes: 44 additions & 0 deletions viewport_helpers.ex
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,44 @@
    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
    27 changes: 27 additions & 0 deletions viewport_resize_hook.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,27 @@
    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)
    }
    }