add some more docs

This commit is contained in:
maddalax 2024-09-24 12:39:16 -05:00
parent 8e4afbede0
commit 2b8ba6e1aa
13 changed files with 280 additions and 25 deletions

View file

@ -2,10 +2,16 @@ package partials
import (
"github.com/maddalax/htmgo/framework/h"
"time"
)
func SamplePartial(ctx *h.RequestContext) *h.Partial {
return h.NewPartial(h.Div(h.P(h.Text(" asdasasds"))))
func CurrentTimePartial(ctx *h.RequestContext) *h.Partial {
now := time.Now()
return h.NewPartial(
h.Div(
h.Pf("The current time is %s", now.Format(time.RFC3339)),
),
)
}
func NewPartial(ctx *h.RequestContext) *h.Partial {

View file

@ -43,8 +43,6 @@ func RenderMarkdown(reader io.Reader) bytes.Buffer {
parser.WithAutoHeadingID(),
),
goldmark.WithRendererOptions(
html.WithHardWraps(),
html.WithXHTML(),
html.WithUnsafe(),
),
goldmark.WithExtensions(

View file

@ -1,3 +1,68 @@
## **Introduction**
htmgo is a lightweight pure go way to build interactive websites / web applications using go & htmx.
We give you the utilities to build html using pure go code in a reusable way (go functions are components) while also providing htmx functions to add interactivity to your app.
```go
func DocsPage(ctx *h.RequestContext) *h.Page {
assets := ctx.Get("embeddedMarkdown").(*embed.FS)
pages := dirwalk.WalkPages("md/docs", assets)
return h.NewPage(base.RootPage(
h.Div(
h.Class("flex flex-col md:flex-row gap-4 justify-center mb-12"),
partials.DocSidebar(pages),
h.Div(
h.Class("flex flex-col justify-center items-center mt-6"),
h.List(pages, func(page *dirwalk.Page, index int) *h.Element {
return h.Div(
h.Class("border-b border-b-slate-300 w-full pb-8 mb-8"),
MarkdownContent(ctx,
page.FilePath,
partials.CreateAnchor(page.Parts)),
)
}),
),
),
))
}
```
**This site was written with htmgo!**
<br>
**Quick overview**
1. Server side rendered html, deploy as a single binary
2. Built in live reloading
3. Built in support for various libraries such as tailwindcss, htmx
4. Go functions are components, no special syntax neccessary to learn
5. Many composable utility functions to streamline development and reduce boilerplate
```go
func ChangeTab(ctx *h.RequestContext) *h.Partial {
service := tasks.NewService(ctx.ServiceLocator())
list, _ := service.List()
tab := ctx.QueryParam("tab")
return h.SwapManyPartialWithHeaders(ctx,
h.PushQsHeader(ctx, h.NewQs("tab", tab)),
List(list, tab),
Footer(list, tab),
)
}
```
Example: **h.SwapManyPartialWithHeaders** to swap out multiple elements on the page with your response, as well as set a new query string parameter.
<br>
See [#core-concepts](#core-concepts-pages) for more information.

View file

@ -11,8 +11,6 @@ Go: https://go.dev/doc/install
go install github.com/maddalax/htmgo/cli/htmgo@latest
```
tip: GONOPROXY helps because the default proxy server for how go resolves modules appears to have fairly long caching on it, so without this env variable, an old version may get installed.
**2. Create new project**
@ -24,7 +22,7 @@ htmgo template
this will ask you for a new app name, and it will clone our starter template to a new directory it creates with your app name.
<br>
**3. Running the dev server**
htmgo has built in live reload on the dev server, to use this, run this command in the root of your project
@ -43,9 +41,9 @@ htmgo run
##### **4. Core concepts**
View the [core concepts](/docs#concepts) of how to use htmgo, such as adding pages, using partials, routing, etc.
View the [core concepts](/docs#core-concepts-pages) of how to use htmgo, such as adding pages, using partials, routing, etc.
<br>
**5. Building for production**
htmgo cli can be used to build the application for production as a single binary
@ -59,8 +57,3 @@ it will be output to **./dist**
<br>
## **Troubleshooting:**
**command not found: htmgo**
ensure you installed htmgo above and ensure GOPATH is set in your shell

View file

@ -1,3 +1,94 @@
## Pages ##
Coming soon
Pages are the entry point of an htmgo application.
A simple page may look like:
```go
// route will be automatically registered based on the file name
func HelloHtmgoPage(ctx *h.RequestContext) *h.Page {
return h.NewPage(
h.Html(
h.HxExtension(h.BaseExtensions()),
h.Head(
h.Link("/public/main.css", "stylesheet"),
h.Script("/public/htmgo.js"),
),
h.Body(
h.Pf("Hello, htmgo!"),
),
),
)
}
```
htmgo uses [Echo Go](https://echo.labstack.com/docs/context) as its web server, ***h.RequestContext** is a thin wrapper around **echo.Context**. A page
must return *h.Page, and accept *h.RequestContext as a parameter
<br>
**Auto Registration**
htmgo uses file based routing. This means that we will automatically generate and register your routes with echo based on the files you have in the 'pages' directory.
For example, if you have a directory structure such as:
```bash
pages
index.go
users.go
users.$id //id parameter can be accessed in your page with ctx.Param("id")
```
it will get registered into Echo as follows:
```bash
/
/users
/users/:id
```
You may put any functions you like in your pages file, auto registration will **ONLY** register functions that return ***h.Page**
<br>
**Tips:**
Generally it is it recommended to abstract common parts of your page into its own component and re-use it, such as script tags, including styling, etc.
Example:
```go
func RootPage(children ...h.Ren) *h.Element {
return h.Html(
h.HxExtension(h.BaseExtensions()),
h.Head(
h.Meta("viewport", "width=device-width, initial-scale=1"),
h.Link("/public/main.css", "stylesheet"),
h.Script("/public/htmgo.js"),
h.Style(`
html {
scroll-behavior: smooth;
}
`),
),
h.Body(
h.Class("bg-stone-50 min-h-screen overflow-x-hidden"),
partials.NavBar(false),
h.Fragment(children...),
),
)
}
```
```go
func UserPage(ctx *h.RequestContext) *h.Page {
return h.NewPage(
base.RootPage(
h.Div(
h.Pf("User ID: %s", ctx.Param("id")),
),
))
}
```

View file

@ -1,3 +1,58 @@
## Partials ##
Coming soon
Partials are where things get interesting. Partials allow you to start adding interactivity to your website by swapping in content, setting headers, redirecting, etc.
Partials have a similiar structure to pages. A simple partial may look like:
```go
func CurrentTimePartial(ctx *h.RequestContext) *h.Partial {
now := time.Now()
return h.NewPartial(
h.Div(
h.Pf("The current time is %s", now.Format(time.RFC3339)),
),
)
}
```
This will get automatically registered in the same way that pages are registered, based on the file path. This allows you to reference partials directly via the function itself when rendering them, instead of worrying about the route.
**Example:**
I want to build a page that renders the current time, updating every second. Here is how that may look:
<br>
**pages/time.go**
```go
package pages
func CurrentTimePage(ctx *h.RequestContext) *h.Page {
return h.NewPage(
base.RootPage(
h.GetPartial(
partials.CurrentTimePartial,
"load, every 1s"),
))
}
```
**partials/time.go**
```go
package partials
func CurrentTimePartial(ctx *h.RequestContext) *h.Partial {
now := time.Now()
return h.NewPartial(
h.Div(
h.Pf("The current time is %s", now.Format(time.RFC3339)),
),
)
}
```
When the page load, the partial will be loaded in via htmx, and then swapped in every 1 second. With this
little amount of code and zero written javascript, you have a page that shows the current time and updates
every second.

View file

@ -22,7 +22,7 @@ func RootPage(children ...h.Ren) *h.Element {
`),
),
h.Body(
h.Class("bg-neutral-50 min-h-screen overflow-x-hidden"),
h.Class("bg-stone-50 min-h-screen overflow-x-hidden"),
partials.NavBar(false),
h.Fragment(children...),
),

View file

@ -6,7 +6,6 @@ import (
"htmgo-site/internal/dirwalk"
"htmgo-site/pages/base"
"htmgo-site/partials"
"strings"
)
func DocsPage(ctx *h.RequestContext) *h.Page {
@ -15,12 +14,22 @@ func DocsPage(ctx *h.RequestContext) *h.Page {
return h.NewPage(base.RootPage(
h.Div(
h.Class("flex gap-4 justify-center mb-12"),
h.Class("flex flex-col md:flex-row gap-4 justify-center mb-12"),
partials.DocSidebar(pages),
h.Div(
h.Class("flex flex-col justify-center items-center mt-6 gap-12"),
h.Class("flex flex-col justify-center items-center mt-6"),
h.List(pages, func(page *dirwalk.Page, index int) *h.Element {
return MarkdownContent(ctx, page.FilePath, strings.Join(page.Parts, "-"))
anchor := partials.CreateAnchor(page.Parts)
return h.Div(
h.Class("border-b border-b-slate-300 w-full pb-8 mb-8"),
MarkdownContent(ctx, page.FilePath, anchor),
h.Div(
h.Class("ml-4 pl-1 mt-2 bg-rose-200"),
h.If(anchor == "core-concepts-partials",
h.GetPartial(partials.CurrentTimePartial, "load, every 1s"),
),
),
)
}),
),
h.Div(

View file

@ -30,7 +30,7 @@ func MarkdownContent(ctx *h.RequestContext, path string, id string) *h.Element {
return h.Div(
h.If(id != "", h.Id(id)),
h.Article(
h.Class("prose max-w-[95vw] md:max-w-2xl px-4 prose-code:text-black"),
h.Class("prose max-w-[95vw] md:max-w-3xl px-4 prose-code:text-black prose-p:my-1"),
h.Raw(renderer.RenderFile(path, embeddedMd)),
),
)

16
htmgo-site/pages/time.go Normal file
View file

@ -0,0 +1,16 @@
package pages
import (
"github.com/maddalax/htmgo/framework/h"
"htmgo-site/pages/base"
"htmgo-site/partials"
)
func CurrentTimePage(ctx *h.RequestContext) *h.Page {
return h.NewPage(
base.RootPage(
h.GetPartial(
partials.CurrentTimePartial,
"load, every 1s"),
))
}

View file

@ -17,6 +17,12 @@ func formatPart(part string) string {
return part
}
func CreateAnchor(parts []string) string {
return strings.Join(h.Map(parts, func(part string) string {
return strings.ReplaceAll(strings.ToLower(formatPart(part)), " ", "-")
}), "-")
}
func partsToName(parts []string) string {
builder := strings.Builder{}
for i, part := range parts {
@ -51,7 +57,7 @@ func DocSidebar(pages []*dirwalk.Page) *h.Element {
grouped := groupByFirstPart(pages)
return h.Div(
h.Class("px-3 py-2 pr-6 min-h-[(calc(100%))] min-h-screen bg-neutral-50 border-r border-r-slate-300"),
h.Class("px-3 py-2 pr-6 md:min-h-[(calc(100%))] md:min-h-screen bg-neutral-50 border-r border-r-slate-300"),
h.Div(
h.H4(h.Text("Contents"), h.Class("mt-4 text-slate-900 font-bold mb-3")),
h.Div(
@ -62,7 +68,8 @@ func DocSidebar(pages []*dirwalk.Page) *h.Element {
h.Div(
h.Class("pl-4 flex flex-col"),
h.List(entry.Value, func(page *dirwalk.Page, index int) *h.Element {
anchor := strings.Join(page.Parts, "-")
anchor := CreateAnchor(page.Parts)
println(anchor)
return h.A(
h.Href("#"+anchor),
h.Text(partsToName(page.Parts)),

View file

@ -0,0 +1,15 @@
package partials
import (
"github.com/maddalax/htmgo/framework/h"
"time"
)
func CurrentTimePartial(ctx *h.RequestContext) *h.Partial {
now := time.Now()
return h.NewPartial(
h.Div(
h.Pf("The current time is %s", now.Format(time.RFC3339)),
),
)
}

View file

@ -1,5 +1,5 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["**/*.go", "**/*.js"],
content: ["**/*.go"],
plugins: [require('@tailwindcss/typography')],
};