sake92 / hepek

Typesafe HTML templates and static site generator in pure Scala
https://sake92.github.io/hepek/
Apache License 2.0
104 stars 10 forks source link

Add HTMX deps and attrs #275

Closed sake92 closed 6 months ago

sake92 commented 6 months ago

Fixes #273

CC: @carlos-verdes

I wanted to dig into HTMX for a long time, but didnt have much chance.. 😄
Always liked the approach of "server-side-html + a sprinkle of JS".
HTMX makes it waaay easier to add some dynamic stuff into your page.


This PR enables you to write this:

import ba.sake.hepek.htmx.*
import ba.sake.hepek.html.HtmlPage
import ba.sake.hepek.scalatags.all.*

trait MyPage extends HtmlPage with HtmxDependencies

object IndexView extends MyPage:
  override def bodyContent = div(
    button(hx.post := "/some-url", hx.swap := "outerHTML")(
      "Click me!"
    )
  )

I think it's enough to get us started.
Few things to mention from your example in the issue:

carlos-verdes commented 6 months ago

This is amazing, more than enough to start. I wanted to add only enums when there are no open text available but I think it's almost never as the example you put, so better to keep just text as you did.

carlos-verdes commented 5 months ago

One quick question, how to add extra plugin dependencies with your current solution? If you give me one example I can raise the PR

This is what I have now with "sse" plugin:


import ba.sake.hepek.html.*

trait HtmxDependencies extends PageDependencies:

  protected val dependencies: List[String] = List("https://unpkg.com/htmx.org")

  def withExtension(extension: String): HtmxDependencies =
    new HtmxDependencies:
      override val dependencies: List[String] = this.dependencies :+ extension

  override def scriptURLs: List[String] = dependencies

object HtmxDependencies:

  val Default = new HtmxDependencies {}

  val WithSSE = Default.withExtension(HtmxExtensions.SseExtension)

object HtmxExtensions:
  val SseExtension = "https://unpkg.com/htmx.org/dist/ext/sse.js"
sake92 commented 5 months ago

TLDR:

override def scriptURLs = super.scriptURLs .appended("https://unpkg.com/htmx.org/dist/ext/sse.js")

The HtmxDependencies and similar are just starter-kits, so it's easier to start working with HTMX(or whatever other *Dependencies you use..).
In production deployments you'd usually download the JS, and reference it from your server, so you don't depend on CDN and other servers.

I did a similar thing you want to achieve with PrismJS lang and plugins.
There is a full list of them here: https://github.com/sake92/hepek/blob/master/hepek-components/shared/src/main/scala/ba/sake/hepek/prismjs/PrismConsts.scala And then I use it here in deps definition: https://github.com/sake92/hepek/blob/master/hepek-components/shared/src/main/scala/ba/sake/hepek/prismjs/PrismDependencies.scala#L10-L20 That way you can pick-and-choose only the languages(dependencies) you need with simply:

// this would only include prism scala JS dependency
override def prismSettings = super.prismSettings.withLanguages("scala")

But I'm not sure if this could be generalized to production-ready setup.
Maybe we could add a customizable DependencyProvider https://github.com/sake92/hepek/blob/master/hepek-components/shared/src/main/scala/ba/sake/hepek/html/DependencyProvider.scala. E.g. if you want to set a prefix or something: MyCustomDepProvider(prefix: String) = .. resolve deps with that prefix..


Btw I've implemented a bunch of examples from their site in my Sharaf framework:
https://github.com/sake92/sharaf/tree/main/examples/scala-cli/htmx :)