adhocteam / pushup

Pushup is for making modern, page-oriented web apps in Go
https://pushup.adhoc.dev
MIT License
840 stars 30 forks source link

Inline partials #33

Closed paulsmith closed 1 year ago

paulsmith commented 1 year ago

Inline partials would allow pages to denote subsections of themselves and allow for the subsections (the inline partials) to be rendered and returned to the client independently without having to render the entire enclosing page.

This would make enhanced hypertext solutions such as htmx trivial to support out of the box in Pushup. The reason is that these systems make AJAX requests for partial HTML responses in order to update portions of an already-loaded document. So the ability to easily and precisely define partials (and not have to deal with complexities like toggling off layouts) would be very helpful in building these types of sites.

Typically, partials are a concept in templating languages where the partial template is stored in its own file which is then transcluded into another template. Inline partials however are partials declared and defined inline some parent or including template. So how would they work and why might this be useful?

For example, let's say we have a Pushup page, architects/index.pushup. That page would be routed via the URL path /architects/. It might look like (note the ^partial keyword):

^{ architects := []string {"Mies van der Rohe", "Jeanne Gang", "Le Corbusier" }

<article>
  <h1>Architects</h1>
  ^partial list {
    <ul>
      ^for _, architect := range architects {
        <li>^architect</li>
      }
    </ul>
  }
</article>

We could map the name of the partial, in this case list, to the end of the page's URL route, giving /architects/list. A client could request /architects/list, and get a response with contents of the list partial only, no enclosing content or layout applied.

(Note that this requires us to determine how to handle having an inline partial and a page named the same (in this case, architects/list.pushup) - whether that is statically disallowed (a compiler error) or one has precedence over the other (with a compiler warning to alert the programmer to the collision), or some other resolution.)

A different page could use htmx to bring in the inline partial content they want:

...
<aside>
  <h3>Architects</h3>
  <div hx-get="/architects/list" hx-trigger="revealed"></div>
</aside>
...

The original page itself could leverage partials for htmx as well. Let's say the list of architects is paginated.

...
  ^partial list {
    <div>
      <ul>
        ^for _, architect := range architects {
          <li>^architect</li>
        }
      </ul>
      <button hx-get="/architects/list?page=^(page + 1)" hx-target="closest div">Next page</button>
    </div>
  }
...

Pushup currently has sections, which allows layouts to render content from pages in specific parts of the HTML template. This is a related concept in that it involves portions of a larger template, but isn't connected to the functionality of inline partials.

paulsmith commented 1 year ago

Partials should be allowed to nest arbitrarily deep.

...
^partial foo {
  <p>
    Foo
    ^partial bar {
      <p>Bar</p>
    }
  </p>
}
...

Would add foo and foo/bar to the end of enclosing page route.