Surface - A component-based library for Phoenix LiveView

@mfilej I also use the suggestion of @derek-zhou

In most app I develop, I need several layouts as they deserve different purpose, and most importantly, they have different designs.

I often use 3 types of layout:

  • a LandingLayout that is used only for the landing page of the website and any related stuff:
    • marketing-oriented design
    • few user interactions
    • components are not reused
  • a AppLayout or MainLayout that is used in the application itself when the user is connected
    • UX oriented design
    • a lot of user interactions
    • components are reused everywhere in the app
  • an AdminLayout that is used only by the team
    • Ugly design (^^)
    • medium user interactions
    • components are reused in the backend

By opening one of my live view, it’s really clear for me which layout is used on and what are the features that layout gives me access to!

In 80% of the time, my live views look like this

<AppLayout
  flashes={{ @flash }}
  current_user={{ @current_user }}
/>
  My Content
</AppLayout>

In the 20 remaining %, I am able to tweak my layout for specific pages explicitly without duplicating it.

<AppLayout
  show_sidebar={{ false }} <-- NO SIDEBAR FOR THAT LIVE VIEW
  flashes={{ @flash }}
  current_user={{ @current_user }}
/>
  My content

  <PageTitle>
    Override the design of the page title for that specific live view
  </PageTitle>

  <RightColumn>
    Useful slottable component that extends my layout and that is not present by default
  </RightColumn>
  # or
  <ProfileRightColumn user={{ current_user }} /> <-- A PREDIFINED RIGHT COLUMN THAT IS EXPLICIT OF ITS INTENT (It is "just" a wrapper arround `<RightColumn>...</RightColumn>` with predifined `props`
</AppLayout>

Finally, here is an example of one of my layout with some comments (I removed classes and I only show the render function):

      <div
        x-data="{ open: false }"
        @keydown.window.escape="open = false"
      >
        <slot name="sidebar" :if={{ @show_sidebar }}> <-- WRAPPING COMPONENTS INTO A SLOT ALLOWS ME TO OVERRIDE THEM EASILY
          <Sidebar id="sidebar" />
        </slot>

        <slot name="secondary_sidebar" /> <-- OPTIONAL EXTENSION

        <div>
          <slot name="header_menu"> <-- LIKE SIDEBAR, IF THE HEADER HAS NOT BEEN OVERRIDED, SHOW THE DEFAULT ONE
            <HeaderMenu id="header-menu" />
          </slot>

          <!-- Main content -->
          <div>

            <!-- Primary column -->
            <main>
              <section>
                <h1>{{ @page_title }}</h1> <-- PROP FOR THAT LAYOUT
                <slot name="default" /> <-- MAIN CONTENT
              </section>
            </main>

            <!-- Optional secondary column -->
            <slot
              name="secondary_column"
              :if={{ show_secondary_column(assigns) }} /> <-- OPTIONNAL EXTENSION WHOSE VISIBILITY IS MANAGED BY THE CHILD COMPONENT
          </div>
        </div>
      </div>
      <FlashMessages flashes={{ @flashes }} /> <-- FLASHES WRAPPER

So yes you have to repeat a few lines of code, but I really believe you gain in clarity and in functionality :slight_smile:

Hope this will help other Surface users! Feel free to comment and get my yours feedback !

10 Likes