pkulchenko / fullmoon

Fast and minimalistic Redbean-based Lua web framework in one file.
MIT License
684 stars 30 forks source link

Processing layouts #19

Closed ghost closed 1 year ago

ghost commented 1 year ago

I see the section for layouts in the readme but can't figure out how it works from the code. Is it not implemented or did I just miss it in there or misunderstand what the placeholder in the readme is about?

In the meantime I found render and rolled my own but I think a built-in would be handy to lots of apps.

pkulchenko commented 1 year ago

@johnmuhl, I'm curious as to what you did and what you were trying to achieve. It's definitely supported, but the support may not be exactly the same as some other frameworks/toolkits do this. I haven't documented it yet, as I wasn't sure if anything else may be needed, so the API may have to change, but so far it looks like what's there already should be sufficient.

If you can describe your example (and the solution you came up with) maybe I can help to see how it can be simplified or what elements may need to be incorporated into the framework. Thanks!

ghost commented 1 year ago

Most pages all have the same header/footer and just the content changes. A few pages need custom layouts. The layouts just need a single "outlet" where the page specific template is rendered.

-- .init.lua
fm.setTemplate({ "/templates/", fmt = "fmt" })
fm.serveTemplate = function (tmpl, opts, layout)
  layout = layout or "_layout"

  return FM.serveContent(layout, {
    tmpl = tmpl,
    opts = opts,
  })
end
<!-- _layout.fmt -->
<html>
<head>...</head>
<body>
  <nav>...</nav>
  <header>...</header>
  {%= render(tmpl, opts) %}
  <footer>...</footer>
</body>
</html>

Then I call fm.serveTemplate("profile", {...}) instead of fm.serveContent("profile", {...}).

pkulchenko commented 1 year ago

Yes, you can definitely do that and it's going to work. Despite using Perl for 15+ years (or maybe because of it), I'm not a big fan of implicit behaviors/magic, so in a situation like yours, I'd use the same template and just call it exactly as you do, but use it explicitly: fm.serveContent(layout, {tmpl = tmpl, opts = opts}).

You can definitely use the method you're showing, but I'd like to encourage more explicit usage, so will likely keep things are they are. I do need to update the documentation though (as you see the templates are a bit under-documented), so am going to cover this as one of the cases. I'll reference this ticket when the documentation is updated.

ghost commented 1 year ago

I started with the serveContent version you show but it felt a little off. Knowing it's the preferred way I'll switch back and see if it grows on me.

pkulchenko commented 1 year ago

Knowing it's the preferred way I'll switch back and see if it grows on me.

Sounds good; please let me know if this still doesn't sit right with you after some further usage.

pkulchenko commented 1 year ago

For those looking at this ticket for layout-related information, I added blocks and detailed template documentation, including layout handling: https://github.com/pkulchenko/fullmoon#using-layouts-and-blocks.

@johnmuhl, let me know if you think something is missing or needs a better explanation. Thanks!