Releases: maddalax/htmgo
V1.0.5
Small release this time, added 2 new JS commands
- h.OnRunInterval(time.Duration, commands ... Command)
Allows you to run JS commands on the specific interval
Usage:
h.Div(
h.OnLoad(
h.RunOnInterval(time.Second,
js.ConsoleLog("this runs a command every 1s"),
js.SetInnerHtml(h.Div()),
js.EvalJs(`alert('you can eval complex js too')`)
),
)
)
- h.RunAfterTimeout(time.Duration, commands ... Command)
Allows you to run JS commands after a specified timeout
h.Div(
h.OnLoad(
h.RunAfterTimeout(time.Second,
js.ConsoleLog("this runs a command once after a second"),
js.SetInnerHtml(h.Div()),
),
)
)
Additional fixes:
Fixes issues where using simple commands such as js.SetText, js.SetInnerHtml were failing when used in things such as Js.EvalCommands due to 'this' not existing. Commands will now always use 'self' if it exists, otherwise 'this'
1.0.4 - Alpha Websocket Support, Partials can be anywhere
Release 1.0.4
Partial Updates
Partials can now be placed anywhere in the project instead of just the partials folder. This is useful for colocating partials and pages together for a simpler setup. The partials folder is no longer necessary.
As long as your function returns *h.Partial
, it will get registered as a partial and can be used, anywhere in the project.
To get these partial updates, make sure to update the htmgo cli
.
Mac / Linux
GOPROXY=direct go install github.com/maddalax/htmgo/cli/htmgo@latest
Windows
set GOPROXY=direct && go install github.com/maddalax/htmgo/cli/htmgo@latest
Websocket Extension Alpha
I released alpha support for a websocket extension. Sample project: https://github.com/maddalax/htmgo/tree/master/examples/ws-example. No documentation is written for it at the moment while I'm testing it out on a larger project I'm building with htmgo. Feel free to look through the ws-example project though.
The extension allows you to push elements to the page and react to events such as OnClick, using ws.OnClick
. The ws extension handles all of the connection management for you, so you can focus on your core logic.
At the moment the there is no documentation for it and things may not work, so unless you are OK with diving deep into the code, I wouldn't utilize it at this moment.
Here is some load testing I did with it though, results look promising, around 50k sockets connected in a machine with 8gb RAM, sending messages every 1s.
Very very early preview, but I'm working on building a larger project with htmgo + the websocket extension. The project will be a dead simple self hosted platform as a service to deploy your apps.
This will be a great test to prove how well htmgo can work for non trivial apps, as well as will be something useful for me personally, and hopefully others.
1.0.3
Discord
htmgo has a new discord, check it out at https://htmgo.dev/discord
New Features
Paths to assets are now included in codegen: #68
Added new JS methods:
- ToggleText
- ToggleTextOnParent
- ToggleTextOnSibling
- ToggleTextOnChildren
- ToggleClassOnChildren
- ToggleClassOnParent
- ToggleClassOnSibling
- EvalCommandsOnSelector
- EvalCommands
Bug Fixes
- Fixed issue where the scripts were being appended as children to the wrong parent element (does not affect which element executes them, but could cause an issue if they were appended to a child and that child was removed)
- Title tag has been added to the starter template in the header
Eval Commands
A new feature htmgo now supports is being able to run js commands against an element by its reference. See https://htmgo.dev/docs/interactivity/eval-commands for more information
Docs / Examples Redesign
https://htmgo.dev/docs have been redesigned to be split over multiple pages, I'm also working on adding more documentation.
https://htmgo.dev/examples has been overhauled as well, working on adding as many examples as I can.
Thanks all!
v1.0.2 - windows fixes
Nothing too major this release, just the following:
- Various windows fixes. I've got a parallels desktop setup now so I can do much better thorough testing on windows (I primarily only use Mac)
- Added charset=utf-8 header when rendering the page
- Reworking the examples page: https://htmgo.dev/examples, planning to add many more examples
For the windows fixes, they were primarily htmgo cli related, so you'll need to run the following to get the latest CLI updates.
set GOPROXY=direct && go install github.com/maddalax/htmgo/cli/htmgo@latest
v1.0.1
What's Changed
- feat:add
ClassF
by @himynamej in #31 - feat: add
Details
&Summary
tag - feat: html to go code formatter now has much better formatting
- feat: service loader now supports 'transient' 21ac153 for services that need to be recreated every time it is requested, unlike a singleton which is only created once.
- feat: added a new formatter for htmgo blocks: https://htmgo.dev/docs#miscellaneous-htmgo-format
Bug Fixes
- Use path by @himynamej in #32
- Use filename instead of absolute path when filtering to replacing old template name with new one by @Sardonyx001 in #42
- htmgo run will now prepare the project properly so you don't have to run htmgo build before (#40)
html to go formatter updates:
htmgo offers a way to convert raw html to htmgo code here: https://htmgo.dev/html-to-go
previously the output was not formatted very well, if you pasted in a large block of html, the output you would get looked something like:
func MyComponent() *h.Element {
return h.Body(
h.Div(h.Class("flex h-screen flex-col justify-between border-e bg-white"),
h.Div(h.Class("px-4 py-6"),
h.Span(h.Class("grid h-10 w-32 place-content-center rounded-lg bg-gray-100 text-xs text-gray-600"), h.Text("Logo")),
h.Ul(h.Class("mt-6 space-y-1"),
h.Li(
h.A(h.Href("#"), h.Class("block rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700"), h.Text("General")),
),
h.Li(
h.Details(h.Class("group [&_summary::-webkit-details-marker]:hidden"),
h.Summary(h.Class("flex cursor-pointer items-center justify-between rounded-lg px-4 py-2 text-gray-500 hover:bg-gray-100 hover:text-gray-700"),
h.Span(h.Class("text-sm font-medium"), h.Text("Teams")),
h.Span(h.Class("shrink-0 transition duration-300 group-open:-rotate-180"),
h.Svg(h.Attribute("xmlns", "http://www.w3.org/2000/svg"), h.Class("size-5"), h.Attribute("viewBox", "0 0 20 20"), h.Attribute("fill", "currentColor"),
h.Tag("path", h.Attribute("fill-rule", "evenodd"), h.Attribute("d", "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"), h.Attribute("clip-rule", "evenodd")),
),
),
),
h.Ul(h.Class("mt-2 space-y-1 px-4"),
h.Li(
h.A(h.Href("#"), h.Class("block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-700"), h.Text("Banned Users")),
),
h.Li(
h.A(h.Href("#"), h.Class("block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-700"), h.Text("Calendar")),
),
),
),
),
h.Li(
h.A(h.Href("#"), h.Class("block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-700"), h.Text("Billing")),
),
h.Li(
h.A(h.Href("#"), h.Class("block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-700"), h.Text("Invoices")),
),
h.Li(
h.Details(h.Class("group [&_summary::-webkit-details-marker]:hidden"),
h.Summary(h.Class("flex cursor-pointer items-center justify-between rounded-lg px-4 py-2 text-gray-500 hover:bg-gray-100 hover:text-gray-700"),
h.Span(h.Class("text-sm font-medium"), h.Text("Account")),
h.Span(h.Class("shrink-0 transition duration-300 group-open:-rotate-180"),
h.Svg(h.Attribute("xmlns", "http://www.w3.org/2000/svg"), h.Class("size-5"), h.Attribute("viewBox", "0 0 20 20"), h.Attribute("fill", "currentColor"),
h.Tag("path", h.Attribute("fill-rule", "evenodd"), h.Attribute("d", "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"), h.Attribute("clip-rule", "evenodd")),
),
),
),
h.Ul(h.Class("mt-2 space-y-1 px-4"),
h.Li(
h.A(h.Href("#"), h.Class("block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-700"), h.Text("Details")),
),
h.Li(
h.A(h.Href("#"), h.Class("block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-700"), h.Text("Security")),
),
h.Li(
h.Form(h.Action("#"),
h.Button(h.Type("submit"), h.Class("w-full rounded-lg px-4 py-2 text-sm font-medium text-gray-500 [text-align:_inherit] hover:bg-gray-100 hover:text-gray-700"), h.Text("Logout")),
),
),
),
),
),
),
),
h.Div(h.Class("sticky inset-x-0 bottom-0 border-t border-gray-100"),
h.A(h.Href("#"), h.Class("flex items-center gap-2 bg-white p-4 hover:bg-gray-50"),
h.Img(h.Alt(""), h.Src("https://images.unsplash.com/photo-1600486913747-55e5470d6f40?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1770&q=80"), h.Class("size-10 rounded-full object-cover")),
h.Div(
h.P(h.Class("text-xs"),
h.Strong(h.Class("block font-medium"), h.Text("Eric Frusciante")),
h.Span(h.Text("[email protected]")),
),
),
),
),
),
)
}
Changes have been made to it so now it formats it properly like so:
func MyComponent() *h.Element {
return h.Body(
h.Div(
h.Class("flex h-screen flex-col justify-between border-e bg-white"),
h.Div(
h.Class("px-4 py-6"),
h.Span(
h.Class("grid h-10 w-32 place-content-center rounded-lg bg-gray-100 text-xs text-gray-600"),
h.Text("Logo"),
),
h.Ul(
h.Class("mt-6 space-y-1"),
h.Li(
h.A(
h.Href("#"),
h.Class("block rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700"),
h.Text("General"),
),
),
h.Li(
h.Details(
h.Class("group [&_summary::-webkit-details-marker]:hidden"),
h.Summary(
h.Class("flex cursor-pointer items-center justify-between rounded-lg px-4 py-2 text-gray-500 hover:bg-gray-100 hover:text-gray-700"),
h.Span(
h.Class("text-sm font-medium"),
h.Text("Teams"),
),
h.Span(
h.Class("shrink-0 transition duration-300 group-open:-rotate-180"),
h.Svg(
h.Attribute("xmlns",
"http://www.w3.org/2000/svg",
),
h.Class("size-5"),
h.Attribute("viewBox",
"0 0 20 20",
),
h.Attribute("fill",
"currentColor",
),
h.Tag("path",
h.Attribute("fill-rule",
"evenodd",
),
h.Attribute("d",
"M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z",
),
h.Attribute("clip-rule",
"evenodd",
),
),
),
),
),
h.Ul(
h.Class("mt-2 space-y-1 px-4"),
h.Li(
h.A(
h.Href("#"),
h.Class("block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-700"),
h.Text("Banned Users"),
),
),
h.Li(
h.A(
h.Href("#"),
h.Class("block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-700"),
h.Text("Calendar"),
),
),
),
),
),
h.Li(
h.A(
h.Href("#"),
h.Class("block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-700"),
h.Text("Billing"),
),
),
h.Li(
h.A(
h.Href("#"),
h.Class("block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-700"),
h.Text("Invoices"),
),
),
h.Li(
h.Details(
h.Class("group [&_summary::-webkit-details-marker]:hidden"),
h.Summary(
h.Class("flex cursor-pointer items-center justify-between rounded-lg px-4 py-2 text-gray-500 hover:bg-gray-100 hover:text-gray-700"),
h.Span(
h.Class("text-sm font-medium"),
h.Text("Account"),
),
h.Span(
h.Class("shrink-0 transition duration-300 group-open:-rotate-180"),
h.Svg(
h.Attribute("xmlns",
"http://www.w3.org/2000/svg",
),
h.Class("size-5"),
h.Attribute("viewBox",
"0 0 20 20",
),
h.Attribute("fill",
"currentColor",
),
h.Tag("path",
h.Attribute("fill-rule",
"evenodd",
),
h.Attribute("d",
"M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z",
),
h.Attribute("clip-rule",
"evenodd",
),
),
),
),
),
h.Ul(
h.Class("mt-2 space-y-1 px-4"),
h.Li(
h.A(
h.Href("#"),
h.Class("block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-700"),
h.Text("Details"),
),
),
h.Li(
h.A(
h.Href("#"),
h.Class("block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-700"),
h.Text("Security"),
),
),
h.Li(
h.Form(
h.Action("#"),
h.Button(
h.Type("submit"),
h.Cla...
v1.0.0 Stable Release
I am excited to announce the stable release of HTMGO v1.0.0! After two months in alpha this release brings the stability and performance enhancements needed for production use.
The API's are now stable and can be considered safe from breaking changes.
Thanks everyone!
v0.3.7
- Added a few helper methods to h.RequestContext
// redirect to a specific location
func (c *RequestContext) Redirect(path string, code int)
// set cookie
func (c *RequestContext) SetCookie(cookie *http.Cookie)
func (c *RequestContext) IsHttpPost() bool
func (c *RequestContext) IsHttpGet() bool
func (c *RequestContext) IsHttpPut() bool
func (c *RequestContext) IsHttpDelete() bool
-
Fixed bug with
HxOnMutationError
-
Added support for returning 'nil' in page or partials. This allows you to write your own response (such as redirecting), without having to return a page or partial, just return nil
Usage:
func IndexPage(ctx *h.RequestContext) *h.Page {
u, ok := user.GetUserOrRedirect(ctx)
if !ok {
return nil
}
return h.NewPage(
RootPage(UserProfilePage(u)),
)
}
-
Updated htmx to swap content if the http status code is 400 or 422. It normally does not do this by default but it is important to show error messages in the case of 400's. Generally 400's are from our own code, so we should be to control what gets swapped in and show proper error messages.
-
Added
h.EmptyPage()
to return a blank page
v0.3.6
What's Changed
- Added a way to configure html via a yaml file (htmgo.yml)
Simply place a htmgo.yml in the root of your project. The following is supported as of now:
# htmgo configuration
# if tailwindcss is enabled, htmgo will automatically compile your tailwind and output it to assets/dist
tailwind: true
# which directories to ignore when watching for changes, supports glob patterns through https://github.com/bmatcuk/doublestar
watch_ignore: [".git", "node_modules", "dist/*"]
# files to watch for changes, supports glob patterns through https://github.com/bmatcuk/doublestar
watch_files: ["**/*.go", "**/*.css", "**/*.md"]
Important: If you already have the htmgo CLI installed, make sure to run GOPROXY=direct go install github.com/maddalax/htmgo/cli/htmgo@latest
to install the latest version.
Full Changelog: v0.3.5...v0.3.6
v0.3.5
- Updated OnLoad event handler to always be called on any element (not just browser supported ones such as Script, Body, Img, etc)
This means if you need run a command / eval js against a specific element when it loads in (on initial load or even after swap), you can do so.
Example:
h.Div(
h.OnLoad(
js.EvalJs(`self.focus()`)
)
)
You can reference the current element using 'self' or 'element' if you are evaluating JS on a parent or sibling.
- Removed usage of html.EscapeString on GetPartialPathWithQs
v0.3.4
What's Changed
- Update watcher to include newly added directories
- Fix GetPartialPath 404ing if calling it from a nested route (#17) thanks @Pitasi
- Add a few utility methods to h.RequestContext
func (c *RequestContext) FormValue(key string)
func (c *RequestContext) Header(key string)
func (c *RequestContext) UrlParam(key string)
func (c *RequestContext) QueryParam(key string)
func (c *RequestContext) IsBoosted() bool
func (c *RequestContext) IsHxRequest() bool
func (c *RequestContext) HxPromptResponse()
func (c *RequestContext) HxTargetId()
func (c *RequestContext) HxTriggerName()
func (c *RequestContext) HxTriggerId()
func (c *RequestContext) HxCurrentBrowserUrl()
Also added
func GetRequestContext(r *http.Request) *RequestContext {
return r.Context().Value(RequestContextKey).(*RequestContext)
}
Usage:
app.Router.Get("/test", func(writer http.ResponseWriter, request *http.Request) {
ctx := h.GetRequestContext(request)
})
For if you need to get the h.RequestContext from an http.Request. This is useful if you are doing your own routing but still want to use h.RequestContext to pass to other things such as partials or other pages.
Full Changelog: v0.3.3...v0.3.4