updates to site, fixes for windows

This commit is contained in:
maddalax 2024-09-23 14:41:43 -05:00
parent 2ca816a1e4
commit c6a0d0e985
18 changed files with 239 additions and 35 deletions

View file

@ -69,6 +69,11 @@ func downloadTailwindCli() {
distro = "linux-arm64"
case os == "linux" && arch == "amd64":
distro = "linux-x64"
case os == "windows" && arch == "amd64":
distro = "windows-x64"
case os == "windows" && arch == "arm64":
distro = "windows-arm64"
default:
log.Fatal(fmt.Sprintf("Unsupported OS/ARCH: %s/%s", os, arch))
}

View file

@ -7,6 +7,7 @@ import (
"os"
"os/exec"
"path/filepath"
"runtime"
"slices"
"strings"
"syscall"
@ -178,7 +179,10 @@ func RunMany(commands []string, flags ...RunFlag) error {
func Run(command string, flags ...RunFlag) error {
parts := strings.Fields(command)
cmd := exec.Command(parts[0], parts[1:]...)
if runtime.GOOS != "windows" {
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
}
if slices.Contains(flags, Silent) {
cmd.Stdout = nil

View file

@ -90,6 +90,10 @@ func Raw(text string) *RawContent {
return NewRawContent(text)
}
func Style(text string) Ren {
return Tag("style", Text(text))
}
func MultiLineQuotes(text string) string {
return "`" + text + "`"
}
@ -140,6 +144,19 @@ func Input(inputType string, children ...Ren) Ren {
}
}
func IterMap[T any](m map[string]T, mapper func(key string, value T) *Element) *Element {
node := &Element{
tag: "",
children: make([]Ren, len(m)),
}
index := 0
for key, value := range m {
node.children[index] = mapper(key, value)
index++
}
return node
}
func List[T any](items []T, mapper func(item T, index int) *Element) *Element {
node := &Element{
tag: "",

View file

@ -0,0 +1,78 @@
package datastructures
// OrderedMap is a generic data structure that maintains the order of keys.
type OrderedMap[K comparable, V any] struct {
keys []K
values map[K]V
}
type Entry[K comparable, V any] struct {
Key K
Value V
}
// Entries returns the key-value pairs in the order they were added.
func (om *OrderedMap[K, V]) Entries() []Entry[K, V] {
entries := make([]Entry[K, V], len(om.keys))
for i, key := range om.keys {
entries[i] = Entry[K, V]{
Key: key,
Value: om.values[key],
}
}
return entries
}
// NewOrderedMap creates a new OrderedMap.
func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V] {
return &OrderedMap[K, V]{
keys: []K{},
values: make(map[K]V),
}
}
// Set adds or updates a key-value pair in the OrderedMap.
func (om *OrderedMap[K, V]) Set(key K, value V) {
// Check if the key already exists
if _, exists := om.values[key]; !exists {
om.keys = append(om.keys, key) // Append key to the keys slice if it's a new key
}
om.values[key] = value
}
// Get retrieves a value by key.
func (om *OrderedMap[K, V]) Get(key K) (V, bool) {
value, exists := om.values[key]
return value, exists
}
// Keys returns the keys in the order they were added.
func (om *OrderedMap[K, V]) Keys() []K {
return om.keys
}
// Values returns the values in the order of their keys.
func (om *OrderedMap[K, V]) Values() []V {
values := make([]V, len(om.keys))
for i, key := range om.keys {
values[i] = om.values[key]
}
return values
}
// Delete removes a key-value pair from the OrderedMap.
func (om *OrderedMap[K, V]) Delete(key K) {
if _, exists := om.values[key]; exists {
// Remove the key from the map
delete(om.values, key)
// Remove the key from the keys slice
for i, k := range om.keys {
if k == key {
om.keys = append(om.keys[:i], om.keys[i+1:]...)
break
}
}
}
}

View file

@ -4,6 +4,8 @@ import (
"github.com/maddalax/htmgo/framework/h"
"io/fs"
"os"
"slices"
"strconv"
"strings"
)
@ -13,8 +15,8 @@ type Page struct {
Parts []string
}
func WalkPages(dir string, system fs.FS) []Page {
pages := make([]Page, 0)
func WalkPages(dir string, system fs.FS) []*Page {
pages := make([]*Page, 0)
fs.WalkDir(system, dir, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
@ -23,7 +25,7 @@ func WalkPages(dir string, system fs.FS) []Page {
if !d.IsDir() && (strings.HasSuffix(name, ".md") || strings.HasSuffix(name, ".go")) {
fullPath := strings.Replace(path, dir, "", 1)
fullPath = strings.TrimSuffix(fullPath, ".md")
pages = append(pages, Page{
pages = append(pages, &Page{
RoutePath: fullPath,
FilePath: path,
Parts: h.Filter(strings.Split(fullPath, string(os.PathSeparator)), func(item string) bool {
@ -33,5 +35,23 @@ func WalkPages(dir string, system fs.FS) []Page {
}
return nil
})
var getRouteOrder = func(page *Page) int {
fileName := page.Parts[len(page.Parts)-1]
if len(fileName) > 1 && fileName[1] == '_' {
num, err := strconv.ParseInt(fileName[0:1], 10, 64)
if err != nil {
return 0
}
page.Parts[len(page.Parts)-1] = fileName[2:]
return int(num)
}
return 0
}
slices.SortFunc(pages, func(a *Page, b *Page) int {
return getRouteOrder(a) - getRouteOrder(b)
})
return pages
}

View file

@ -46,7 +46,7 @@ func main() {
__htmgo.RegisterPages(e)
pages.RegisterMarkdown(e, "md", MarkdownAssets, func(ctx echo.Context, path string) error {
return pages.MarkdownHandler(ctx.(*h.RequestContext), path)
return pages.MarkdownHandler(ctx.(*h.RequestContext), path, "")
})
},
})

View file

@ -0,0 +1,3 @@
## **Introduction**
htmgo is a lightweight pure go way to build interactive websites / web applications using go & htmx.

View file

@ -1,11 +1,14 @@
## **Getting Started**
##### **Prerequisites:**
Go: https://go.dev/doc/install
<br>
##### 1. **Install htmgo**
```bash
GONOPROXY=github.com/maddalax go install github.com/maddalax/htmgo/cli/htmgo@latest
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.

View file

@ -0,0 +1,3 @@
## Pages ##
Coming soon

View file

@ -0,0 +1,3 @@
## Partials ##
Coming soon

View file

@ -1 +1,4 @@
Coming soon
**Todo List MVC**
[Github](https://github.com/maddalax/htmgo/tree/master/examples/todo-list)
[Live Demo](https://todo-example.htmgo.dev)

View file

@ -15,6 +15,11 @@ func RootPage(children ...h.Ren) *h.Element {
h.Raw(`
<script async defer src="https://buttons.github.io/buttons.js"></script>
`),
h.Style(`
html {
scroll-behavior: smooth;
}
`),
),
h.Body(
h.Class("bg-neutral-50 min-h-screen overflow-x-hidden"),

View file

@ -5,6 +5,8 @@ import (
"github.com/maddalax/htmgo/framework/h"
"htmgo-site/internal/dirwalk"
"htmgo-site/pages/base"
"htmgo-site/partials"
"strings"
)
func DocsPage(ctx *h.RequestContext) *h.Page {
@ -13,14 +15,17 @@ func DocsPage(ctx *h.RequestContext) *h.Page {
return h.NewPage(base.RootPage(
h.Div(
h.Class("flex flex-col justify-center items-center"),
h.List(pages, func(page dirwalk.Page, index int) *h.Element {
return MarkdownContent(ctx, page.FilePath)
h.Class("flex 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.List(pages, func(page *dirwalk.Page, index int) *h.Element {
return MarkdownContent(ctx, page.FilePath, strings.Join(page.Parts, "-"))
}),
),
h.Div(
h.Class("min-h-12"),
),
),
)
))
}

View file

@ -5,5 +5,5 @@ import (
)
func IndexPage(ctx *h.RequestContext) *h.Page {
return h.NewPage(MarkdownPage(ctx, "md/index.md"))
return h.NewPage(MarkdownPage(ctx, "md/index.md", ""))
}

View file

@ -8,15 +8,15 @@ import (
"htmgo-site/pages/base"
)
func MarkdownHandler(ctx *h.RequestContext, path string) error {
return h.HtmlView(ctx, h.NewPage(MarkdownPage(ctx, path)))
func MarkdownHandler(ctx *h.RequestContext, path string, id string) error {
return h.HtmlView(ctx, h.NewPage(MarkdownPage(ctx, path, id)))
}
func MarkdownPage(ctx *h.RequestContext, path string) *h.Element {
func MarkdownPage(ctx *h.RequestContext, path string, id string) *h.Element {
return base.RootPage(
h.Div(
h.Class("w-full p-4 flex flex-col justify-center items-center"),
MarkdownContent(ctx, path),
MarkdownContent(ctx, path, id),
h.Div(
h.Class("min-h-12"),
),
@ -24,10 +24,11 @@ func MarkdownPage(ctx *h.RequestContext, path string) *h.Element {
)
}
func MarkdownContent(ctx *h.RequestContext, path string) *h.Element {
func MarkdownContent(ctx *h.RequestContext, path string, id string) *h.Element {
embeddedMd := ctx.Get("embeddedMarkdown").(*embed.FS)
renderer := service.Get[markdown.Renderer](ctx.ServiceLocator())
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.Raw(renderer.RenderFile(path, embeddedMd)),

View file

@ -74,7 +74,6 @@ func NavBar(expanded bool) *h.Element {
)
return h.Div(
h.Class("mb-4"),
h.Id("navbar"),
prelease,
MobileNav(expanded),

View file

@ -1,22 +1,77 @@
package partials
import "github.com/maddalax/htmgo/framework/h"
import (
"github.com/maddalax/htmgo/framework/h"
"htmgo-site/internal/datastructures"
"htmgo-site/internal/dirwalk"
"strings"
)
func formatPart(part string) string {
if part[1] == '_' {
part = part[2:]
}
part = strings.ReplaceAll(part, "-", " ")
part = strings.ReplaceAll(part, "_", " ")
part = strings.Title(part)
return part
}
func partsToName(parts []string) string {
builder := strings.Builder{}
for i, part := range parts {
if i == 0 {
continue
}
part = formatPart(part)
builder.WriteString(part)
builder.WriteString(" ")
}
return builder.String()
}
func groupByFirstPart(pages []*dirwalk.Page) *datastructures.OrderedMap[string, []*dirwalk.Page] {
grouped := datastructures.NewOrderedMap[string, []*dirwalk.Page]()
for _, page := range pages {
if len(page.Parts) > 0 {
section := page.Parts[0]
existing, has := grouped.Get(section)
if !has {
existing = []*dirwalk.Page{}
grouped.Set(section, existing)
}
grouped.Set(section, append(existing, page))
}
}
return grouped
}
func DocSidebar(pages []*dirwalk.Page) *h.Element {
grouped := groupByFirstPart(pages)
func SideBar() *h.Element {
return h.Div(
h.Class("w-40 top-[57px] absolute min-h-screen bg-neutral-50 border border-r-slate-300 p-3"),
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.Div(
h.Class("max-w-prose mx-auto"),
h.H4(h.Text("Contents"), h.Class("mt-4 text-slate-900 font-bold mb-3")),
h.Div(
h.Class("flex flex-col gap-4"),
h.A(
h.Href("/docs"),
h.Text("Docs"),
),
h.A(
h.Href("/examples"),
h.Text("Examples"),
h.List(grouped.Entries(), func(entry datastructures.Entry[string, []*dirwalk.Page], index int) *h.Element {
return h.Div(
h.P(h.Text(formatPart(entry.Key)), h.Class("text-slate-800 font-bold")),
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, "-")
return h.A(
h.Href("#"+anchor),
h.Text(partsToName(page.Parts)),
h.ClassX("text-slate-900", map[string]bool{}),
)
}),
),
)
}),
),
),
)