woutdp / live_svelte

Svelte inside Phoenix LiveView with seamless end-to-end reactivity
https://hexdocs.pm/live_svelte
MIT License
1.2k stars 46 forks source link

Is it Possible to use Layout with LiveSvelte #90

Closed Maxino22 closed 11 months ago

Maxino22 commented 11 months ago

Hi , I was thinking of converting my layout currently in heex to livesvelte in order to use features like mobile menu toggling easily

currently seeing I can use <.svelte/> inside the html.heex but for layout inner content comes in play is there a way

woutdp commented 11 months ago

<.svelte/> should work in a layout file, can you show some code of where it doesn't work?

Maxino22 commented 11 months ago

It does work my question was how will I achieve the setting of dynamic content

          <main class="lg:col-span-9 xl:col-span-10">
            <%= @inner_content %>
          </main>

as soo in the svelte file

woutdp commented 11 months ago

There's 2 ways to achieve this if I understand correctly:

Method 1 with slots (not recomnended) You could use slots, although I don't recommend this as this functionality is a bit fragile:

Layout

<.svelte ... >
    <%= @inner_content %>
</.svelte>

Svelte

<main class="lg:col-span-9 xl:col-span-10">
    <slot/>
</main>

Method 2 with props What I'd recommend is passing @inner_content as a prop to svelte. This will be more robust.

Heex

<.svelte ... props={%{inner_content: @inner_content}} />

Svelte

<script>
    export let inner_content
</script>

<main class="lg:col-span-9 xl:col-span-10">
    {@html inner_content}
</main>
Maxino22 commented 11 months ago

Thanks what you recommend looks perfect

tedkulp commented 7 months ago

In case anyone else is having issues using this, use:

<.svelte ... props={%{inner_content: Phoenix.HTML.safe_to_string(@inner_content)}}/>

I did originally try to use the "fragile" method above, but it gave me issues encoding errors. The 2nd method with the above change works beautifully!

Maxino22 commented 7 months ago

Thanks for sharing well mine doesn't work here is my layout HEEX

<!DOCTYPE html>
<html lang="en" class="[scrollbar-gutter:stable]">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="csrf-token" content={get_csrf_token()} />
    <.live_title suffix=" · Realest8 Platform">
      <%= assigns[:page_title] || "Home" %>
    </.live_title>
    <link phx-track-static rel="stylesheet" href={~p"/assets/app.css"} />
    <link phx-track-static rel="icon" href={~s(/images/favicon.ico)} />

    <script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}>
    </script>
  </head>

  <body>

<.svelte name="TenantLayout" props={%{inner_content: Phoenix.HTML.safe_to_string(@inner_content)}} ssr={false}/>
  </body>

</html>

and here is the TenantLayout Component

<script>
export let inner_content

</script>
  <header class="relative bg-white shadow border-b">
    <div class="mx-auto max-w-7xl">
      <div class="flex justify-between h-20 p-5 items-center">
        <div class="flex-shrink-0 flex items-center">
          <a href="/tenant" data-phx-link="redirect" data-phx-link-state="push" >

            <img class="block h-12 w-auto" src="/images/logo.png" alt="Workflow" />
          </a>

        </div>

        <div class="hidden sm:flex sm:space-x-8">
          <a class=" block sm:inline-flex items-center px-2 pt-1 font-bold border-r8-green border-b-4 text-r8-green" href="/tenant" data-phx-link="redirect" data-phx-link-state="push" >
            Home
          </a>
          <a class=" block sm:inline-flex items-center px-2 pt-1 font-bold border-r8-green border-b-4 text-r8-green" href="/tenant/invoices" data-phx-link="redirect" data-phx-link-state="push" >
            Payment History
          </a>
          <a class=" block sm:inline-flex items-center px-2 pt-1 font-bold border-r8-green border-b-4 text-r8-green" href="/tenant/leases" data-phx-link="redirect" data-phx-link-state="push" >
            Lease
          </a>

        </div>

        <button

          id="profile-btn"
          class="hidden h-8 pl-2 pr-1 border w-16 border-gray-300 rounded-full sm:flex justify-between items-center"
        >
          <img src="/images/main-menu.png" alt="main-menu" class="h-4 w-4" />
          <div class="bg-white rounded-full flex focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-rose-500">
              <div class="rounded-full h-6 w-6 bg-r8-Orange text-white flex justify-center items-center text-sm">
                       MM
                      </div>
          </div>
        </button>

        <button  class="sm:hidden">
          <img src="/images/main-menu.png" alt="main-menu" class="h-5 w-5" />
        </button>
        <!-- menu -->
        <ul

          id="menu"
          class="origin-top-right absolute z-10 top-14 right-5 mt-2 w-48 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 py-1 focus:outline-none"
        >
          <li>
            <a class="block py-2 px-4 text-sm text-gray-700" href="/tenant/profile" data-phx-link="redirect" data-phx-link-state="push" >
              Your Profile
            </a>

          </li>

          <li>
            <a
              href="/log_out"
              method="delete"
              class="block py-2 px-4 text-sm text-gray-700"
            >
              Log out
          </a>
          </li>
        </ul>
      </div>
    </div>

    <nav

    >
      <div class="border-t border-gray-300 pt-4">
        <div class="mt-3 max-w-3xl mx-auto px-2 space-y-1 sm:px-4">
          <!-- User navigation links -->
          <a href="/tenant" class="block rounded-md py-2 px-3 text-base font-medium text-gray-500 hover:bg-gray-50 hover:text-gray-900" data-phx-link="redirect" data-phx-link-state="push">Home</a>
          <a href="/tenant/invoices" class="block rounded-md py-2 px-3 text-base font-medium text-gray-500 hover:bg-gray-50 hover:text-gray-900" data-phx-link="redirect" data-phx-link-state="push">Payment History</a>
          <a href="/tenant/leases" class="block rounded-md py-2 px-3 text-base font-medium text-gray-500 hover:bg-gray-50 hover:text-gray-900" data-phx-link="redirect" data-phx-link-state="push">Leases</a>
          <a href="log_out" class="block rounded-md py-2 px-3 text-base font-medium text-gray-500 hover:bg-gray-50 hover:text-gray-900" data-phx-link="redirect" data-phx-link-state="push">Logout</a>

        </div>
      </div>
    </nav>
  </header>

  {@html inner_content}

this is all that is shown my page (inner content is not rendered

def render(assigns) do
    ~H"""
    <.svelte
      name="tenant/TenantHome"
      props={%{tenant: @tenant, invoice: @invoice, property: @property}}
      socket={@socket}
      ssr={false}
    />
    """
  end

this is the liveview for that specific page

Maxino22 commented 7 months ago

Screenshot 2024-02-28 at 23 21 14 image of what i see

tedkulp commented 7 months ago

I started having other issues after I posted that. First, it would only work on pages with other svelte components in them (i think). I fixed that with:

def render_inner_content(inner_content) do
    inner_content
    |> Phoenix.HTML.Safe.to_iodata()
    |> to_string()
  end

and

<.svelte name="layout" props={%{inner_content: render_inner_content(@inner_content)}} />

But afterwards, further live_view actions (especially ones with other svelte components in them) were flakey and would sometimes just give a blank page. Auth stuff didn't work at all. I didn't feel like debugging it anymore, as it was just a test, so I ended up just backing it all out.