Full Code of haatos/goshipit for AI

main efe198c76672 cached
144 files
569.6 KB
207.2k tokens
392 symbols
1 requests
Download .txt
Showing preview only (610K chars total). Download the full file or copy to clipboard to get everything.
Repository: haatos/goshipit
Branch: main
Commit: efe198c76672
Files: 144
Total size: 569.6 KB

Directory structure:
gitextract_6j5602nm/

├── .gitignore
├── LICENSE
├── Makefile
├── cmd/
│   ├── generate/
│   │   └── main.go
│   ├── gsi/
│   │   └── main.go
│   └── server/
│       └── main.go
├── go.mod
├── go.sum
├── input.css
├── internal/
│   ├── assets/
│   │   ├── content/
│   │   │   ├── cli.md
│   │   │   ├── getting_started.md
│   │   │   └── types.md
│   │   ├── embed.go
│   │   ├── generated/
│   │   │   ├── component_code_map.json
│   │   │   ├── component_example_code_map.json
│   │   │   └── components.go
│   │   └── public/
│   │       └── static/
│   │           ├── css/
│   │           │   ├── chroma.css
│   │           │   └── custom.css
│   │           └── js/
│   │               ├── alpine.js
│   │               └── datastar.js
│   ├── components.go
│   ├── echo.go
│   ├── handler/
│   │   ├── components.go
│   │   ├── error.go
│   │   ├── htmx.go
│   │   ├── input_validation.go
│   │   ├── pages.go
│   │   └── render.go
│   ├── markdown/
│   │   └── markdown.go
│   ├── markdown.go
│   ├── model/
│   │   └── generation.go
│   ├── settings.go
│   └── views/
│       ├── components/
│       │   ├── accordion.templ
│       │   ├── active_search.templ
│       │   ├── alert.templ
│       │   ├── anchor.templ
│       │   ├── avatar.templ
│       │   ├── banner.templ
│       │   ├── breadcrumbs.templ
│       │   ├── card.templ
│       │   ├── carousel.templ
│       │   ├── chat.templ
│       │   ├── checkbox.templ
│       │   ├── collapse.templ
│       │   ├── combobox.templ
│       │   ├── countdown.templ
│       │   ├── date_picker.templ
│       │   ├── diff.templ
│       │   ├── drawer.templ
│       │   ├── dropdown.templ
│       │   ├── fab.templ
│       │   ├── features.templ
│       │   ├── file_input.templ
│       │   ├── footer.templ
│       │   ├── hero.templ
│       │   ├── hover_3d_card.templ
│       │   ├── infinite_scroll.templ
│       │   ├── input.templ
│       │   ├── lazy_load.templ
│       │   ├── menu.templ
│       │   ├── modal.templ
│       │   ├── pagination.templ
│       │   ├── pricing.templ
│       │   ├── radio.templ
│       │   ├── range.templ
│       │   ├── rating.templ
│       │   ├── select.templ
│       │   ├── skeleton.templ
│       │   ├── stats.templ
│       │   ├── status.templ
│       │   ├── steps.templ
│       │   ├── swap.templ
│       │   ├── table.templ
│       │   ├── tabs.templ
│       │   ├── testimonial.templ
│       │   ├── text_rotate.templ
│       │   ├── textarea.templ
│       │   ├── time_slot_picker.templ
│       │   ├── timeline.templ
│       │   ├── toast.templ
│       │   ├── toggle.templ
│       │   └── tooltip.templ
│       ├── custom/
│       │   └── toast.templ
│       ├── embed.go
│       ├── examples/
│       │   ├── accordion.templ
│       │   ├── active_search.templ
│       │   ├── alert.templ
│       │   ├── anchor.templ
│       │   ├── avatar.templ
│       │   ├── banner.templ
│       │   ├── breadcrumbs.templ
│       │   ├── card.templ
│       │   ├── carousel.templ
│       │   ├── chat.templ
│       │   ├── checkbox.templ
│       │   ├── collapse.templ
│       │   ├── combobox.templ
│       │   ├── countdown.templ
│       │   ├── date_picker.templ
│       │   ├── diff.templ
│       │   ├── drawer.templ
│       │   ├── dropdown.templ
│       │   ├── fab.templ
│       │   ├── features.templ
│       │   ├── file_input.templ
│       │   ├── footer.templ
│       │   ├── hero.templ
│       │   ├── hover_3d_card.templ
│       │   ├── infinite_scroll.templ
│       │   ├── input.templ
│       │   ├── lazy_load.templ
│       │   ├── menu.templ
│       │   ├── modal.templ
│       │   ├── pagination.templ
│       │   ├── pricing.templ
│       │   ├── radio.templ
│       │   ├── range.templ
│       │   ├── rating.templ
│       │   ├── select.templ
│       │   ├── skeleton.templ
│       │   ├── stats.templ
│       │   ├── status.templ
│       │   ├── steps.templ
│       │   ├── swap.templ
│       │   ├── table.templ
│       │   ├── tabs.templ
│       │   ├── testimonial.templ
│       │   ├── text_rotate.templ
│       │   ├── textarea.templ
│       │   ├── time_slot_picker.templ
│       │   ├── timeline.templ
│       │   ├── toast.templ
│       │   ├── toggle.templ
│       │   └── tooltip.templ
│       ├── pages/
│       │   ├── base.templ
│       │   ├── cli.templ
│       │   ├── client_error.templ
│       │   ├── component.templ
│       │   ├── index.templ
│       │   └── server_error.templ
│       └── scripts/
│           └── copy_button.templ
├── package.json
├── readme.md
└── tailwind.config.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.vscode/
.env
*_templ.go
*_templ.txt
bin/
node_modules/
internal/assets/public/static/css/tw.css
.DS_Store


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2024 Tomi Haapalainen

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Makefile
================================================
.DEFAULT_GOAL := dev

GOOS := "linux"
GOARCH := "amd64"

deploy:
	npx @tailwindcss/cli -i input.css -o ./internal/assets/public/static/css/tw.css --minify
	go run cmd/generate/main.go
	templ generate
	GOOS=$(GOOS) GOARCH=$(GOARCH) go build -ldflags "-s -w" -o bin/new-main cmd/server/main.go
	scp 'bin/new-main' $(user)@$(ip):/opt/goshipit/
	ssh $(user)@$(ip) "sudo service goshipit stop"
	ssh $(user)@$(ip) "rm /opt/goshipit/main"
	ssh $(user)@$(ip) "mv /opt/goshipit/new-main /opt/goshipit/main"
	ssh $(user)@$(ip) "sudo service goshipit start"

gen:
	go run cmd/generate/main.go

tw:
	@npx @tailwindcss/cli -i input.css -o ./internal/assets/public/static/css/tw.css --watch

dev: gen
	@templ generate -watch -proxyport=7332 -proxy="http://localhost:8080" -open-browser=false -cmd="go run cmd/server/main.go"


================================================
FILE: cmd/generate/main.go
================================================
package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"go/format"
	"io/fs"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/haatos/goshipit/internal/markdown"
	"github.com/haatos/goshipit/internal/model"
)

const (
	componentCodeMapJSONPath        = "internal/assets/generated/component_code_map.json"
	componentExampleCodeMapJSONPath = "internal/assets/generated/component_example_code_map.json"
	componentsDir                   = "internal/views/components/"
	componentsHandlerPath           = "internal/handler/components.go"
	examplesDir                     = "internal/views/examples/"
	generatedDir                    = "internal/assets/generated"
	generatedComponentsPath         = "internal/assets/generated/components.go"
)

func main() {
	generateComponentCodeMap()
	generateComponentExampleCodeMap()
	generateComponentMap()
}

func generateComponentCodeMap() {
	m := model.ComponentCodeMap{}
	if err := filepath.Walk(componentsDir, func(path string, info fs.FileInfo, err error) error {
		if !info.IsDir() && strings.HasSuffix(path, ".templ") {
			if err := getComponentCode(path, info, m); err != nil {
				return err
			}
		}
		return nil
	}); err != nil {
		log.Fatal(err)
	}

	if err := os.RemoveAll(generatedDir); err != nil {
		log.Fatal(err)
	}
	if err := os.Mkdir(generatedDir, 0755); err != nil {
		log.Fatal(err)
	}

	b, err := json.MarshalIndent(m, "", "  ")
	if err != nil {
		log.Fatal(err)
	}

	fg, err := os.Create(componentCodeMapJSONPath)
	if err != nil {
		log.Fatal(err)
	}
	defer fg.Close()

	if _, err := fg.Write(b); err != nil {
		log.Fatal(err)
	}
}

func getComponentCode(path string, info fs.FileInfo, fmap model.ComponentCodeMap) error {
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	defer f.Close()

	componentName := strings.TrimSuffix(info.Name(), ".templ")

	scanner := bufio.NewScanner(f)
	function := []string{}
	inFunction := false
	description := []string{}
	inDescription := false
	daisyUIURL := ""
	var category string
	for scanner.Scan() {
		line := scanner.Text()
		if category == "" {
			category = strings.TrimPrefix(line, "// ")
			continue
		}
		if strings.HasPrefix(line, "// https://daisyui.com") {
			daisyUIURL = strings.TrimPrefix(line, "// ")
		}
		if strings.HasPrefix(line, "/*") {
			inDescription = true
			continue
		}
		if strings.HasPrefix(line, "*/") {
			inDescription = false
			continue
		}
		if inDescription {
			description = append(description, line)
			continue
		}
		if strings.HasPrefix(line, "type ") || strings.HasPrefix(line, "templ ") {
			inFunction = true
		}
		if inFunction {
			function = append(function, line)
		}
	}
	if _, ok := fmap[category]; !ok {
		fmap[category] = []model.ComponentCode{}
	}
	fmap[category] = append(
		fmap[category],
		model.ComponentCode{
			Name:        componentName,
			Code:        markdown.CodeSliceToMarkdown(function),
			Description: strings.Join(description, "\n"),
			DaisyUIURL:  daisyUIURL,
		})
	return nil
}

func generateComponentExampleCodeMap() {
	m := model.ComponentExampleCodeMap{}
	if err := filepath.Walk(examplesDir, func(path string, info fs.FileInfo, err error) error {
		if !info.IsDir() && strings.HasSuffix(path, ".templ") {
			if err := addComponentExampleToMap(m, info, path); err != nil {
				return err
			}
		}
		return nil
	}); err != nil {
		log.Fatal(err)
	}

	for comName := range m {
		for i := range m[comName] {
			if err := addComponentExampleBackendParts(m, comName, i); err != nil {
				log.Fatal(err)
			}
		}
	}

	b, err := json.MarshalIndent(m, "", "  ")
	if err != nil {
		log.Fatal(err)
	}

	fg, err := os.Create(componentExampleCodeMapJSONPath)
	if err != nil {
		log.Fatal(err)
	}
	defer fg.Close()

	if _, err := fg.Write(b); err != nil {
		log.Fatal(err)
	}
}

func addComponentExampleToMap(
	m model.ComponentExampleCodeMap,
	info fs.FileInfo,
	path string,
) error {
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	defer f.Close()

	functionLines := []string{}
	var functionName string
	componentName := strings.TrimSuffix(info.Name(), ".templ")
	m[componentName] = []model.ComponentCode{}
	inExample := false
	description := []string{}
	title := ""
	inDescription := false

	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.HasPrefix(line, "// example") {
			if inExample {
				m[componentName] = append(
					m[componentName],
					model.ComponentCode{
						Name:        functionName,
						Code:        markdown.CodeSliceToMarkdown(functionLines),
						Title:       title,
						Description: strings.Join(description, "\n"),
					})
				functionName = ""
				functionLines = []string{}
				description = []string{}
			}
			inExample = true
			continue
		}

		if strings.HasPrefix(line, "// ") && !strings.HasPrefix(line, "// example") {
			title = strings.TrimPrefix(line, "// ")
			continue
		}

		if strings.HasPrefix(line, "/*") {
			inDescription = true
			continue
		}
		if strings.HasPrefix(line, "*/") {
			inDescription = false
			continue
		}
		if inDescription {
			description = append(description, line)
		}

		if strings.HasPrefix(line, "templ ") && functionName == "" {
			functionName = strings.TrimPrefix(line, "templ ")
			functionName = functionName[:strings.Index(functionName, "(")]
		}

		if inExample && !inDescription {
			functionLines = append(functionLines, line)
		}
	}

	m[componentName] = append(
		m[componentName],
		model.ComponentCode{
			Name:        functionName,
			Code:        markdown.CodeSliceToMarkdown(functionLines),
			Title:       title,
			Description: strings.Join(description, "\n"),
		},
	)
	return nil
}

func addComponentExampleBackendParts(
	m model.ComponentExampleCodeMap,
	comName string,
	index int,
) error {
	f, err := os.Open(componentsHandlerPath)
	if err != nil {
		return err
	}
	defer f.Close()

	inExampleHandler := false
	functionLines := []string{}
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.HasPrefix(line, fmt.Sprintf("// %s", m[comName][index].Name)) {
			if inExampleHandler {
				inExampleHandler = false
				m[comName][index].Handler = markdown.CodeSliceToMarkdown(functionLines)
				break
			} else {
				inExampleHandler = true
			}
			continue
		}

		if inExampleHandler {
			functionLines = append(functionLines, line)
		}
	}
	return nil
}

func generateComponentMap() {
	functionNames := []string{}
	if err := filepath.Walk(examplesDir, func(path string, info fs.FileInfo, err error) error {
		if !info.IsDir() && strings.HasSuffix(path, ".templ") {
			f, err := os.Open(path)
			if err != nil {
				return err
			}

			inExample := false

			scanner := bufio.NewScanner(f)
			for scanner.Scan() {
				line := scanner.Text()
				if strings.HasPrefix(line, "// example") {
					inExample = true
				}

				if inExample && strings.HasPrefix(line, "templ ") {
					functionName := strings.TrimPrefix(line, "templ ")
					functionName = functionName[:strings.Index(functionName, "(")]
					functionNames = append(functionNames, functionName)
					inExample = false
				}
			}
		}
		return nil
	}); err != nil {
		log.Fatal(err)
	}

	writeGeneratedFunctions(functionNames)
}

func writeGeneratedFunctions(functionNames []string) {
	// write functions into a buffer
	src := bytes.NewBuffer(nil)
	src.WriteString("package generated\n\n")
	src.WriteString("import (\n")
	src.WriteString("\t\"github.com/a-h/templ\"\n")
	src.WriteString("\t\"github.com/haatos/goshipit/internal/views/examples\"\n")
	src.WriteString(")\n\n")
	src.WriteString("var ExampleComponents = map[string]templ.Component{\n")
	for _, name := range functionNames {
		fmt.Fprintf(src, "\t\"%s\": examples.%s(),\n", name, name)
	}
	src.WriteString("}\n")

	// format the buffer's bytes using gofmt
	b, err := format.Source(src.Bytes())
	if err != nil {
		log.Fatal(err)
	}

	// write the file
	fg, err := os.Create(generatedComponentsPath)
	if err != nil {
		log.Fatal(err)
	}
	defer fg.Close()
	if _, err := fg.Write(b); err != nil {
		log.Fatal(err)
	}
}


================================================
FILE: cmd/gsi/main.go
================================================
package main

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"slices"
	"strings"

	"github.com/haatos/goshipit/internal/views"
)

var componentsDirParts = []string{"internal", "views", "components"}

func main() {
	code := run(os.Stdout, os.Stderr, os.Args)
	if code != 0 {
		os.Exit(code)
	}
}

const usageText string = `usage: gsi <command> [<args>...]

gsi - GoShip.it CLI

commands:
  add <name>      Add a component to internal/views/components
  remove <name>   Remove a component from internal/views/components
  list            List all available components

`

func run(stdout, stderr io.Writer, args []string) int {
	if len(args) < 2 {
		_, _ = fmt.Fprint(stdout, usageText)
		return 64
	}

	switch args[1] {
	case "add":
		if len(args) < 3 {
			_, _ = fmt.Fprint(stdout, usageText)
			return 64
		}
		name := strings.Join(args[2:], " ")
		return runAddCommand(stderr, name)
	case "remove":
		if len(args) < 3 {
			_, _ = fmt.Fprint(stdout, usageText)
			return 64
		}
		name := strings.Join(args[2:], " ")
		return runRemoveCommand(stdout, name)
	case "list":
		return runListCommand(stdout)
	}

	return 1
}

func runAddCommand(stderr io.Writer, name string) int {
	name = strings.ReplaceAll(name, " ", "_")
	b, err := views.ComponentFS.ReadFile("components/" + name + ".templ")
	if err != nil {
		_, _ = fmt.Fprintf(stderr, "component '%s' does not exist\n", name)
		return 1
	}
	packageIndex := bytes.Index(b, []byte("package"))
	b = b[packageIndex:]

	dirPath := filepath.Join(componentsDirParts...)
	fileName := fmt.Sprintf("%s.templ", name)
	fullPath := filepath.Join(dirPath, fileName)

	componentExists := true
	if _, err := os.Stat(fullPath); errors.Is(err, os.ErrNotExist) {
		componentExists = false
	}

	if componentExists {
		var ans string
		fmt.Printf("Component '%s' already exists. Replace [Y/n]: ", name)
		if _, err := fmt.Scan(&ans); err != nil {
			log.Fatal(err)
		}
		if ans == "n" {
			return 0
		}
		fmt.Printf("Replacing component '%s'...\n", name)
	}

	if err := os.MkdirAll(dirPath, os.ModePerm); err != nil {
		log.Fatal("err making directories '", dirPath+"':", err)
	}

	f, err := os.Create(fullPath)
	if err != nil {
		log.Fatal("err creating file '", fullPath+"':", err)
	}
	if _, err := f.Write(b); err != nil {
		log.Fatal("err writing component to '", fullPath+"':", err)
	}

	return 0
}

func runRemoveCommand(stdout io.Writer, name string) int {
	name = strings.ReplaceAll(name, " ", "_")
	dirPath := filepath.Join(componentsDirParts...)
	fileName := fmt.Sprintf("%s.templ", name)
	templFileName := fmt.Sprintf("%s_templ.go", name)
	if err := os.Remove(filepath.Join(dirPath, fileName)); err == nil {
		_, _ = fmt.Fprintf(stdout, "Removed '%s'\n", filepath.Join(dirPath, fileName))
	}
	if err := os.Remove(filepath.Join(dirPath, templFileName)); err != nil {
		_, _ = fmt.Fprintf(stdout, "Removed '%s'\n", filepath.Join(dirPath, templFileName))
	}
	return 0
}

func runListCommand(stdout io.Writer) int {
	entries, err := views.ComponentFS.ReadDir("components")
	if err != nil {
		log.Fatal(err)
	}
	_, _ = fmt.Fprint(stdout, "Run 'gsi add <name>' to add a component\n\n")
	m := make(map[string][]string)
	for _, entry := range entries {
		b, err := views.ComponentFS.ReadFile(filepath.Join("components", entry.Name()))
		if err != nil {
			log.Fatal(err)
		}
		split := bytes.Split(b, []byte("\n"))
		category := split[0]
		category = bytes.TrimPrefix(category, []byte("// "))
		category = bytes.ReplaceAll(category, []byte("_"), []byte(" "))
		categoryStr := string(category)
		m[categoryStr] = append(m[categoryStr], strings.TrimSuffix(entry.Name(), ".templ"))
	}

	keys := make([]string, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}

	slices.Sort(keys)

	for _, key := range keys {
		_, _ = fmt.Fprint(stdout, strings.ToUpper(key)+"\n")
		_, _ = fmt.Fprint(stdout, "=======================\n")
		for _, comp := range m[key] {
			p := filepath.Join("internal", "views", "components", comp+".templ")
			_, err := os.Stat(p)
			exists := err == nil
			line := strings.ReplaceAll(comp, "_", " ")
			if exists {
				line += " ✓"
			}
			line += "\n"

			_, _ = fmt.Fprint(stdout, line)
		}
		_, _ = fmt.Fprint(stdout, "\n")
	}

	return 0
}


================================================
FILE: cmd/server/main.go
================================================
package main

import (
	"github.com/haatos/goshipit/internal"
	"github.com/haatos/goshipit/internal/assets"
	"github.com/haatos/goshipit/internal/handler"
	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"

	_ "github.com/mattn/go-sqlite3"
)

func main() {
	internal.ReadDotenv()
	internal.Settings = internal.NewSettings()

	e := echo.New()
	e.HTTPErrorHandler = handler.ErrorHandler
	loggerFormat := "${method} ${uri} [${status}] (${latency_human}) | ${short_file}:${line} | ${message}\n"
	e.Logger.SetHeader(loggerFormat)

	config := internal.GetRateLimiterConfig()
	e.Use(middleware.RateLimiterWithConfig(config))

	e.Use(
		middleware.LoggerWithConfig(middleware.LoggerConfig{
			Format: loggerFormat,
		}),
		middleware.GzipWithConfig(middleware.GzipConfig{
			Skipper: middleware.DefaultSkipper,
			Level:   3,
		}),
	)

	publicFS := echo.MustSubFS(assets.PublicFS, "public")
	e.StaticFS("/", publicFS)

	e.GET("/", handler.GetIndexPage)
	e.GET("/about", handler.GetAboutPage)
	e.GET("/get-started", handler.GetGettingStartedPage)
	e.GET("/types", handler.GetTypesPage)
	e.GET("/cli", handler.GetCLIPage)
	e.GET("/component-anchors", handler.GetComponentAnchors)
	e.GET("/privacy", handler.GetPrivacyPolicyPage)
	e.GET("/terms-of-service", handler.GetTermsOfServicePage)

	e.GET("/components/:category/:name", handler.GetComponentPage)
	e.GET("/components/search", handler.GetComponentSearch)

	// handlers for component examples
	e.POST("/validate/string/:name", handler.PostValidateString)
	e.GET("/infinite-scroll", handler.GetInfiniteScrollExample)
	e.GET("/infinite-scroll-rows", handler.GetInfiniteScrollExampleRows)
	e.GET("/active-search", handler.GetActiveSearchExample)
	e.GET("/lazy-load", handler.GetLazyLoadExample)
	e.GET("/models", handler.GetCascadingSelectExample)
	e.GET("/pagination-pages", handler.GetPaginationExamplePage)
	e.POST("/combobox/:name/:value", handler.PostCombobox)
	e.POST("/combobox-submit/:name", handler.PostComboboxSubmit)
	e.DELETE("/modal-confirm", handler.DeleteModalExample)
	e.POST("/datepicker/select", handler.PostDatePickerSelectDay)
	e.GET("/datepicker", handler.GetDatePicker)
	e.GET("/datepicker/monthpicker", handler.GetDatePickerMonthPicker)
	e.GET("/datepicker/yearpicker", handler.GetDatePickerYearPicker)
	e.GET("/timeslotpicker", handler.GetTimeSlotPicker)
	e.POST("/timeslotpicker/reserve", handler.PostTimeSlotPickerReserve)
	// handlers for component examples

	internal.GracefulShutdown(e, internal.Settings.Port)
}


================================================
FILE: go.mod
================================================
module github.com/haatos/goshipit

go 1.24

require (
	github.com/PuerkitoBio/goquery v1.10.1
	github.com/a-h/templ v0.3.1001
	github.com/alecthomas/chroma v0.10.0
	github.com/labstack/echo/v4 v4.12.0
	github.com/labstack/gommon v0.4.2
	github.com/mattn/go-sqlite3 v1.14.24
	github.com/russross/blackfriday v1.6.0
	golang.org/x/time v0.7.0
)

require (
	github.com/andybalholm/cascadia v1.3.3 // indirect
	github.com/dlclark/regexp2 v1.11.4 // indirect
	github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
	github.com/mattn/go-colorable v0.1.13 // indirect
	github.com/mattn/go-isatty v0.0.20 // indirect
	github.com/valyala/bytebufferpool v1.0.0 // indirect
	github.com/valyala/fasttemplate v1.2.2 // indirect
	golang.org/x/crypto v0.40.0 // indirect
	golang.org/x/net v0.42.0 // indirect
	golang.org/x/sys v0.34.0 // indirect
	golang.org/x/text v0.27.0 // indirect
)


================================================
FILE: go.sum
================================================
github.com/PuerkitoBio/goquery v1.10.1 h1:Y8JGYUkXWTGRB6Ars3+j3kN0xg1YqqlwvdTV8WTFQcU=
github.com/PuerkitoBio/goquery v1.10.1/go.mod h1:IYiHrOMps66ag56LEH7QYDDupKXyo5A8qrjIx3ZtujY=
github.com/a-h/templ v0.3.943 h1:o+mT/4yqhZ33F3ootBiHwaY4HM5EVaOJfIshvd5UNTY=
github.com/a-h/templ v0.3.943/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
github.com/a-h/templ v0.3.960 h1:trshEpGa8clF5cdI39iY4ZrZG8Z/QixyzEyUnA7feTM=
github.com/a-h/templ v0.3.960/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
github.com/a-h/templ v0.3.977 h1:kiKAPXTZE2Iaf8JbtM21r54A8bCNsncrfnokZZSrSDg=
github.com/a-h/templ v0.3.977/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
github.com/a-h/templ v0.3.1001 h1:yHDTgexACdJttyiyamcTHXr2QkIeVF1MukLy44EAhMY=
github.com/a-h/templ v0.3.1001/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=


================================================
FILE: input.css
================================================
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@source "./internal/views/**/*.templ";
@plugin "daisyui" {
  themes:
    light --default,
    night --prefersdark;
}


================================================
FILE: internal/assets/content/cli.md
================================================
# CLI

## Installation

```
go install github.com/haatos/cmd/gsi
```

Then run `gsi` in your terminal to see a list of commands:

```
usage: gsi <command> [<args>...]

gsi - GoShip.it CLI

commands:
  add <name>      Add a component to internal/views/components
  remove <name>   Remove a component from internal/views/components
  list            List all available components
```

Use the CLI at the root of your application. New components will be added to `internal/views/components/`.


================================================
FILE: internal/assets/content/getting_started.md
================================================
# Getting started

To get started with goship.it in a new project using _Echo_ router:

- Create a new folder for your project
- Initialize the module by running
  - `go mod init github.com/my/package`
  - replace the package with your own repository!
- Get Go modules:
  - `go get -u github.com/labstack/echo/v4`
  - `go get -u github.com/a-h/templ`
- Install Templ CLI:
  - `go install github.com/a-h/templ/cmd/templ@latest`
- Install TailwindCSS and DaisyUI:
  - `npm i -D tailwindcss @tailwindcss/cli @tailwindcss/typography daisyui@latest`
- Create `input.css` at the root of the project with the following contents:

```input.css
@import "tailwindcss" source(none);
@plugin "@tailwindcss/typography";
@source "./internal/views/**/*.templ";
@plugin "daisyui" {
    themes:
        light --default,
        dark --prefersdark;
}
@plugin "daisyui/theme" {
    name: "light";
    default: true;
    prefersdark: false;
    color-scheme: "light";
    --color-base-100: oklch(92% 0 0);
    --color-base-200: oklch(87% 0 0);
    --color-base-300: oklch(70% 0 0);
    --color-base-content: oklch(0% 0 0);
    --color-primary: oklch(55% 0.135 66.442);
    --color-primary-content: oklch(98% 0.018 155.826);
    --color-secondary: oklch(53% 0.157 131.589);
    --color-secondary-content: oklch(98% 0.031 120.757);
    --color-accent: oklch(64% 0.222 41.116);
    --color-accent-content: oklch(98% 0.016 73.684);
    --color-neutral: oklch(43% 0 0);
    --color-neutral-content: oklch(98% 0 0);
    --color-info: oklch(52% 0.105 223.128);
    --color-info-content: oklch(98% 0.019 200.873);
    --color-success: oklch(50% 0.118 165.612);
    --color-success-content: oklch(98% 0.018 155.826);
    --color-warning: oklch(55% 0.195 38.402);
    --color-warning-content: oklch(98% 0.016 73.684);
    --color-error: oklch(52% 0.223 3.958);
    --color-error-content: oklch(97% 0.014 343.198);
    --radius-selector: 0.5rem;
    --radius-field: 0.5rem;
    --radius-box: 0.5rem;
    --size-selector: 0.28125rem;
    --size-field: 0.28125rem;
    --border: 1px;
    --depth: 1;
    --noise: 0;
}
@plugin "daisyui/theme" {
    name: "dark";
    default: false;
    prefersdark: true;
    color-scheme: "dark";
    --color-base-100: oklch(26% 0 0);
    --color-base-200: oklch(20% 0 0);
    --color-base-300: oklch(14% 0 0);
    --color-base-content: oklch(97% 0 0);
    --color-primary: oklch(79% 0.184 86.047);
    --color-primary-content: oklch(28% 0.066 53.813);
    --color-secondary: oklch(64% 0.2 131.684);
    --color-secondary-content: oklch(98% 0.031 120.757);
    --color-accent: oklch(64% 0.222 41.116);
    --color-accent-content: oklch(98% 0.016 73.684);
    --color-neutral: oklch(14% 0 0);
    --color-neutral-content: oklch(98% 0 0);
    --color-info: oklch(71% 0.143 215.221);
    --color-info-content: oklch(98% 0.019 200.873);
    --color-success: oklch(72% 0.219 149.579);
    --color-success-content: oklch(98% 0.018 155.826);
    --color-warning: oklch(70% 0.213 47.604);
    --color-warning-content: oklch(98% 0.016 73.684);
    --color-error: oklch(65% 0.241 354.308);
    --color-error-content: oklch(97% 0.014 343.198);
    --radius-selector: 0.5rem;
    --radius-field: 0.5rem;
    --radius-box: 0.5rem;
    --size-selector: 0.28125rem;
    --size-field: 0.28125rem;
    --border: 1px;
    --depth: 1;
    --noise: 0;
}
```

- Create `Makefile` at the base of your project with the following contents:

```make
tw:
	@npx @tailwindcss/cli -i input.css -o ./public/static/css/tw.css --watch

dev:
	@templ generate -watch -proxyport=7332 -proxy="http://localhost:8080" -open-browser=false -cmd="go run main.go"
```

- Place the following rows in `main.go` (remember to update the components package import path to match your project):

```go
package main

import (
	"net/http"

	"github.com/my/package/internal/views/components"

	"github.com/a-h/templ"
	"github.com/labstack/echo/v4"
)

func main() {
	e := echo.New()

	e.Static("/", "public")

	e.GET("/", func(c echo.Context) error {
		accordion := components.AccordionExample()
		return render(c, accordion)
	})

	e.Start(":8080")
}

func render(c echo.Context, component templ.Component) error {
	buf := templ.GetBuffer()
	defer templ.ReleaseBuffer(buf)

	if err := component.Render(c.Request().Context(), buf); err != nil {
		return err
	}
	return c.HTML(http.StatusOK, buf.String())
}
```

- Create the accordion component `internal/views/components/accordion.templ`:

```go
package components

type AccordionRowProps struct {
	Label string
	Type  string
	Name  string
}

templ AccordionRow(props AccordionRowProps) {
	<div class="collapse collapse-arrow bg-base-300 join-item">
		<input
			if props.Type == "" {
				type="checkbox"
			} else {
				type={ props.Type }
			}
			name={ props.Name }
		/>
		<div class="collapse-title text-xl font-medium">{ props.Label }</div>
		<div class="collapse-content bg-base-200">
			{ children... }
		</div>
	</div>
}

templ AccordionExample() {
	<!DOCTYPE html>
	<html lang="en">
		<head>
			<meta charset="UTF-8"/>
			<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
			<link rel="stylesheet" type="text/css" href="/static/css/tw.css"/>
			<title>Document</title>
		</head>
		<body class="w-full h-full min-h-svh">
			<main>
				<div>
					@AccordionRow(AccordionRowProps{Label: "Accordion row 1", Type: "checkbox"}) {
						<p>This is the first content</p>
					}
					@AccordionRow(AccordionRowProps{Label: "Accordion row 2", Type: "checkbox"}) {
						<p>This is the second content</p>
					}
				</div>
			</main>
		</body>
	</html>
}
```

At this point, the filetree of your project should look something like this:

```sh
.
├── Makefile
├── go.mod
├── go.sum
├── input.css
├── internal
│   └── views
│       └── components
│           └── accordion.templ
├── main.go
├── node_modules
├── package-lock.json
├── package.json
├── public
│   └── static
│       └── css
│           └── tw.css
└── tailwind.config.js
```

If you are using VSCode as your IDE, you should also add a `.vscode/settings.json` with the following contents (or place these settings in some other VSCode configuration file):

```json
{
  "[templ]": {
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "a-h.templ"
  },
  "tailwindCSS.includeLanguages": {
    "templ": "html"
  },
  "emmet.includeLanguages": {
    "templ": "html"
  }
}
```

These will enable TailwindCSS autocompletions and HTML element autocompletions (emmet), as well as automatically formatting `.templ` files when saving.

Finally, you can run the example application by running `make tw` and `make dev` in two separate terminals. The site with the accordion should now be visible at http://localhost:8080.


================================================
FILE: internal/assets/content/types.md
================================================
# Types

## Introduction

Most components use a struct as the input argument. This provides a convenient way to pass default values to the components; struct fields initialize to the respective type's default value. We can use this feature to make some of the fields of a struct optional to make initialization less cumbersome. For example, we can pass the `components.AnchorProps` argument to an anchor element, `<a>`:

```go
package components

type AnchorProps struct {
	Href      string
	Label     string
	LeftIcon  templ.Component
	RightIcon templ.Component
	Attrs     templ.Attributes
	Class     string
}

templ Anchor(props AnchorProps) {
	<a
		if props.Href != "" {
			href={ templ.SafeURL(props.Href) }
		}
		class={ "group flex items-center cursor-pointer", props.Class }
		{ props.Attrs... }
	>
		if props.LeftIcon != nil {
			<div class="inline-block mr-1">
				@props.LeftIcon
			</div>
		}
		{ props.Label }
		if props.RightIcon != nil {
			<div class="inline-block ml-1">
				@props.RightIcon
			</div>
		}
	</a>
}
```

Here we can define the anchor element to optionally have an `href` attribute, or if we choose, a `hx-get` instead:

```go
@components.Anchor(components.AnchorProps{Href: "/"})
@components.Anchor(components.AnchorProps{Attrs: templ.Attributes{"hx-get": "/"}})
```

## Deprecated types

```go
package model

import (
	"time"

	"github.com/a-h/templ"
)

type Accordion struct {
	Label string
	Type  string
	Name  string
}

type ActiveSearchInput struct {
	ID     string
	URL    string
	Target string
	Input  Input
}

type Anchor struct {
	Href      string
	Label     string
	LeftIcon  templ.Component
	RightIcon templ.Component
	Attrs     templ.Attributes
	Class     string
}

type Avatar struct {
	AvatarClass      string
	ContainerClass   string
	Source           string
	Placeholder      string
	PlaceholderClass string
}

type Banner struct {
	Title                 templ.Component
	Description           string
	CallToAction          Button
	SecondaryCallToAction Button
}

type Button struct {
	Label string
	Attrs templ.Attributes
}

type Card struct {
	Title   string
	Content string
	Source  string
	Alt     string
	Class   string
}

type Chat struct {
	Messages []ChatMessage
}

type ChatMessage struct {
	AvatarURL string
	Sender    string
	Time      string
	Message   string
	Footer    string
	Location  string
	Class     string
}

type Checkbox struct {
	ID      string
	Before  string
	After   string
	Name    string
	Checked bool
	Class   string
	Attrs   templ.Attributes
}

type Collapse struct {
	Class        string
	Title        string
	TitleClass   string
	ContentClass string
}

type Combobox struct {
	Label    string
	Name     string
	URL      string
	Options  []string
	Selected []string
}

type CompanyInfo struct {
	Icon        templ.Component
	Name        string
	Description string
	Copyright   string
}

type DatePicker struct {
	Year        int
	Month       int
	Selected    time.Time
	StartOfWeek time.Weekday
}

func (dp DatePicker) Days() []time.Time {
	days := make([]time.Time, 0, 31)
	now := time.Now().UTC()
	start := time.Date(dp.Year, time.Month(dp.Month), 1, 0, 0, 0, 0, now.Location())
	end := start.AddDate(0, 1, -1)
	for end.Weekday() != dp.StartOfWeek {
		end = end.AddDate(0, 0, 1)
	}
	end = end.AddDate(0, 0, -1)

	for start.Weekday() != dp.StartOfWeek {
		start = start.AddDate(0, 0, -1)
	}
	for !start.After(end) {
		days = append(days, start)
		start = start.AddDate(0, 0, 1)
	}
	return days
}

func (dp DatePicker) Months() []time.Time {
	months := make([]time.Time, 12)
	for i := 1; i <= 12; i++ {
		dt := time.Date(dp.Year, time.Month(i), 1, 0, 0, 0, 0, time.Now().Location())
		months[i-1] = dt
	}
	return months
}

type Dropdown struct {
	Label     string
	Class     string
	ListClass string
	Items     []DropdownItem
}

type DropdownItem struct {
	Label string
	Attrs templ.Attributes
}

type Feature struct {
	Icon        templ.Component
	Title       string
	Description string
	URL         string
}

type Image struct {
	Source string
	Alt    string
}

type Input struct {
	ID              string
	Type            string // defaults to "text"
	Label           string
	Name            string
	Value           string
	Placeholder     string
	Err             string
	Attrs           templ.Attributes
	Class           string
	Icon            templ.Component
	Disabled        bool
	DisabledMessage string
	Required        bool
}

type PaginationItem struct {
	URL      string
	Page     int
	Low      int
	High     int
	MaxPages int
}

type Price struct {
	Title            string
	Description      string
	Price            string
	Per              string
	IncludedFeatures []string
	ExcludedFeatures []string
	CallToAction     Button
	Footer           templ.Component
}

type Radio struct {
	Name   string
	Values map[string]string
	Class  string
}

type Range struct {
	ID    string
	Label string
	Name  string
	Value int
	Min   int
	Max   int
	Step  int
	Class string
}

type Rating struct {
	Name  string
	Min   int
	Max   int
	Class string
	Value int
}

type Script struct {
	Source string
	Defer  bool
}

type Select struct {
	ID      string
	Label   string
	Name    string
	Options []SelectOption
	Attrs   templ.Attributes
	Class   string
}

type SelectOption struct {
	Label    string
	Value    string
	Selected bool
	Disabled bool
}

type Stat struct {
	Title       string
	Value       string
	Description string
}

type Status struct {
	Code         int
	Title        string
	Description  string
	ReturnButton Button
}

type Swap struct {
	On    templ.Component
	Off   templ.Component
	Class string
}

type Tabs struct {
	Name         string
	Class        string
	Tabs         []Tab
	ContentClass string
}

type Tab struct {
	Label   string
	Content templ.Component
}

type Testimonial struct {
	Avatar  templ.Component
	Name    string
	Rating  int
	Content string
}

type Textarea struct {
	ID          string
	Label       string
	Name        string
	Placeholder string
	Value       string
	Rows        int
	Err         string
	Class       string
	Attrs       templ.Attributes
}

type TimelineItem struct {
	Start  string
	Middle templ.Component
	End    string
}

type Toast struct {
	Name       string
	ToastClass string
	AlertClass string
}

type Toggle struct {
	ID        string
	Before    string
	After     string
	Name      string
	Checked   bool
	Class     string
	Highlight bool
	Attrs     templ.Attributes
}

type Tooltip struct {
	Tip   string
	Class string
}
```


================================================
FILE: internal/assets/embed.go
================================================
package assets

import "embed"

//go:embed public/*
var PublicFS embed.FS

//go:embed content/*
var ContentFS embed.FS

//go:embed generated/*
var GeneratedFS embed.FS


================================================
FILE: internal/assets/generated/component_code_map.json
================================================
{
  "actions": [
    {
      "name": "dropdown",
      "code": "```go\ntype DropdownProps struct {\n\tLabel     string\n\tClass     string\n\tListClass string\n\tItems     []DropdownItem\n}\n\ntype DropdownItem struct {\n\tLabel string\n\tAttrs templ.Attributes\n}\n\ntempl Dropdown(props DropdownProps) {\n\t\u003cdetails class={ \"dropdown\", props.Class }\u003e\n\t\t\u003csummary class=\"btn m-1\"\u003e{ props.Label }\u003c/summary\u003e\n\t\t\u003cul class={ \"menu dropdown-content\", props.ListClass }\u003e\n\t\t\tfor _, di := range props.Items {\n\t\t\t\t\u003cli\u003e\u003ca { di.Attrs... }\u003e{ di.Label }\u003c/a\u003e\u003c/li\u003e\n\t\t\t}\n\t\t\u003c/ul\u003e\n\t\u003c/details\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/dropdown"
    },
    {
      "name": "fab",
      "code": "```go\ntype FABProps struct {\n\tClass       string\n\tToggle      any // string or templ.Component\n\tToggleClass string\n\tClose       templ.Component\n\tMainAction  templ.Component\n}\n\ntempl FAB(props FABProps) {\n\t\u003cdiv class={ \"fab\", props.Class }\u003e\n\t\t\u003cdiv tabindex=\"0\" role=\"button\" class={ \"btn\", props.ToggleClass }\u003e\n\t\t\tif t, ok := props.Toggle.(string); ok {\n\t\t\t\t{ t }\n\t\t\t} else {\n\t\t\t\t@props.Toggle.(templ.Component)\n\t\t\t}\n\t\t\u003c/div\u003e\n\t\tif props.Close != nil {\n\t\t\t\u003cdiv class=\"fab-close\"\u003e\n\t\t\t\t@props.Close\n\t\t\t\u003c/div\u003e\n\t\t}\n\t\tif props.MainAction != nil {\n\t\t\t\u003cdiv class=\"fab-main-action\"\u003e\n\t\t\t\t@props.MainAction\n\t\t\t\u003c/div\u003e\n\t\t}\n\t\t{ children... }\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/fab"
    },
    {
      "name": "modal",
      "code": "```go\ntype ModalProps struct {\n\tID    string\n\tLabel any\n}\n\ntempl Modal(props ModalProps) {\n\t@modalWrapper(\n\t\tprops,\n\t\ttempl.Attributes{\"onclick\": fmt.Sprintf(\"%s.showModal()\", props.ID)},\n\t) {\n\t\t{ children... }\n\t}\n}\n\ntempl modalWrapper(props ModalProps, attrs templ.Attributes) {\n\t// you can use a string or a templ.Component as the 'label'\n\t// of the modal button\n\tif s, ok := props.Label.(string); ok {\n\t\t\u003cdiv class=\"btn\" { attrs... }\u003e\n\t\t\t{ s }\n\t\t\u003c/div\u003e\n\t} else if c, ok := props.Label.(templ.Component); ok {\n\t\t@c\n\t}\n\t\u003cdialog id={ props.ID } class=\"modal\"\u003e\n\t\t\u003cdiv class=\"modal-box\"\u003e\n\t\t\t{ children... }\n\t\t\u003c/div\u003e\n\t\t\u003cform method=\"dialog\" class=\"modal-backdrop\"\u003e\n\t\t\t\u003cbutton\u003eclose\u003c/button\u003e\n\t\t\u003c/form\u003e\n\t\u003c/dialog\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/modal"
    },
    {
      "name": "swap",
      "code": "```go\ntype SwapProps struct {\n\tOn    templ.Component\n\tOff   templ.Component\n\tClass string\n}\n\ntempl Swap(props SwapProps) {\n\t\u003clabel class={ \"swap\", props.Class }\u003e\n\t\t\u003cinput type=\"checkbox\"/\u003e\n\t\t\u003cdiv class=\"swap-on\"\u003e\n\t\t\t@props.On\n\t\t\u003c/div\u003e\n\t\t\u003cdiv class=\"swap-off\"\u003e\n\t\t\t@props.Off\n\t\t\u003c/div\u003e\n\t\u003c/label\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/swap"
    }
  ],
  "data_display": [
    {
      "name": "accordion",
      "code": "```go\ntype AccordionRowProps struct {\n\tLabel string\n\tType  string\n\tName  string\n}\n\ntempl AccordionRow(props AccordionRowProps) {\n\t\u003cdiv class=\"collapse collapse-arrow bg-base-300 join-item\"\u003e\n\t\t\u003cinput\n\t\t\tif props.Type == \"\" {\n\t\t\t\ttype=\"checkbox\"\n\t\t\t} else {\n\t\t\t\ttype={ props.Type }\n\t\t\t}\n\t\t\tname={ props.Name }\n\t\t/\u003e\n\t\t\u003cdiv class=\"collapse-title text-xl font-medium\"\u003e{ props.Label }\u003c/div\u003e\n\t\t\u003cdiv class=\"collapse-content bg-base-200\"\u003e\n\t\t\t{ children... }\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/accordion"
    },
    {
      "name": "active_search",
      "code": "```go\ntype ActiveSearchInputProps struct {\n\tID         string\n\tURL        string\n\tTarget     string\n\tInputProps InputProps\n}\n\ntempl ActiveSearchInput(props ActiveSearchInputProps) {\n\t\u003cdiv class=\"w-full flex space-x-2 items-center\"\u003e\n\t\t\u003cdiv class=\"flex items-center gap-2 w-full max-w-xs\"\u003e\n\t\t\t\u003cform\n\t\t\t\tid={ props.ID }\n\t\t\t\thx-get={ props.URL }\n\t\t\t\thx-target={ props.Target }\n\t\t\t\thx-swap=\"innerHTML\"\n\t\t\t\thx-trigger={ fmt.Sprintf(\"keyup from:input[name=%s] delay:500ms, search\", props.InputProps.Name) }\n\t\t\t\thx-indicator={ fmt.Sprintf(\"#%s\", props.ID) }\n\t\t\t\tclass=\"w-full relative\"\n\t\t\t\u003e\n\t\t\t\t@Input(props.InputProps)\n\t\t\t\t\u003cdiv class=\"absolute -right-8 top-2\"\u003e\n\t\t\t\t\t\u003cspan id={ props.ID } class=\"htmx-indicator loading loading-sm loading-spinner\"\u003e\u003c/span\u003e\n\t\t\t\t\u003c/div\u003e\n\t\t\t\u003c/form\u003e\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n```"
    },
    {
      "name": "avatar",
      "code": "```go\ntype AvatarProps struct {\n\tAvatarClass      string\n\tContainerClass   string\n\tSource           string\n\tPlaceholder      string\n\tPlaceholderClass string\n}\n\ntempl Avatar(props AvatarProps) {\n\t\u003cdiv class={ \"avatar\", props.AvatarClass }\u003e\n\t\t\u003cdiv class={ props.ContainerClass }\u003e\n\t\t\t\u003cimg src={ props.Source }/\u003e\n\t\t\tif props.Placeholder != \"\" {\n\t\t\t\t\u003cspan class={ props.PlaceholderClass }\u003e{ props.Placeholder }\u003c/span\u003e\n\t\t\t}\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n\ntempl AvatarGroup(class string) {\n\t\u003cdiv class={ \"avatar-group rtl:space-x-reverse\", class }\u003e\n\t\t{ children... }\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/avatar"
    },
    {
      "name": "card",
      "code": "```go\ntype CardProps struct {\n\tTitle   string\n\tContent string\n\tSource  string\n\tAlt     string\n\tClass   string\n}\n\ntempl Card(props CardProps) {\n\t\u003cdiv class={ \"card\", props.Class }\u003e\n\t\tif props.Source != \"\" {\n\t\t\t\u003cfigure\u003e\n\t\t\t\t\u003cimg src={ props.Source } alt={ props.Alt }/\u003e\n\t\t\t\u003c/figure\u003e\n\t\t}\n\t\t\u003cdiv class=\"card-body\"\u003e\n\t\t\t\u003ch2 class=\"card-title\"\u003e{ props.Title }\u003c/h2\u003e\n\t\t\t\u003cp\u003e{ props.Content }\u003c/p\u003e\n\t\t\t\u003cdiv class=\"card-actions justify-end\"\u003e\n\t\t\t\t{ children... }\n\t\t\t\u003c/div\u003e\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/card"
    },
    {
      "name": "carousel",
      "code": "```go\ntype CarouselProps []CarouselProp\n\ntype CarouselProp struct {\n\tSource string\n\tAlt    string\n}\n\ntempl Carousel(props CarouselProps) {\n\t\u003cdiv class=\"carousel carousel-center rounded-box\"\u003e\n\t\tfor _, prop := range props {\n\t\t\t\u003cdiv class=\"carousel-item [\u0026:not(:last-child)]:border-r border-r-base-300\"\u003e\n\t\t\t\t\u003cimg class=\"max-w-xs\" src={ prop.Source } alt={ prop.Alt }/\u003e\n\t\t\t\u003c/div\u003e\n\t\t}\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/carousel"
    },
    {
      "name": "chat",
      "code": "```go\ntype ChatProps []ChatMessageProps\n\ntype ChatMessageProps struct {\n\tAvatarURL string\n\tSender    string\n\tTime      string\n\tMessage   string\n\tFooter    string\n\tLocation  string\n\tClass     string\n}\n\ntempl Chat(props ChatProps) {\n\tfor _, prop := range props {\n\t\t@ChatMessage(prop)\n\t}\n}\n\ntempl ChatMessage(props ChatMessageProps) {\n\t\u003cdiv\n\t\tclass={\n\t\t\t\"chat\",\n\t\t\ttempl.KV(\"chat-start\", props.Location == \"start\"),\n\t\t\ttempl.KV(\"chat-end\", props.Location == \"end\"),\n\t\t}\n\t\u003e\n\t\tif props.AvatarURL != \"\" {\n\t\t\t@Avatar(AvatarProps{ContainerClass: \"chat-image w-10 rounded-full\", Source: props.AvatarURL})\n\t\t}\n\t\t\u003cdiv class=\"chat-header\"\u003e\n\t\t\t{ props.Sender }\n\t\t\t\u003ctime class=\"text-xs opacity-50\"\u003e{ props.Time }\u003c/time\u003e\n\t\t\u003c/div\u003e\n\t\t\u003cdiv class={ \"chat-bubble\", props.Class }\u003e\n\t\t\t{ props.Message }\n\t\t\u003c/div\u003e\n\t\t\u003cdiv class=\"chat-footer\"\u003e\n\t\t\t{ props.Footer }\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/chat"
    },
    {
      "name": "collapse",
      "code": "```go\ntype CollapseProps struct {\n\tClass        string\n\tTitle        string\n\tTitleClass   string\n\tContentClass string\n}\n\ntempl Collapse(props CollapseProps) {\n\t\u003cdiv\n\t\ttabindex=\"0\"\n\t\tclass={ \"collapse\", props.Class }\n\t\u003e\n\t\t\u003cinput type=\"checkbox\"/\u003e\n\t\t\u003cdiv class={ \"collapse-title\", props.TitleClass }\u003e\n\t\t\t{ props.Title }\n\t\t\u003c/div\u003e\n\t\t\u003cdiv class={ \"collapse-content\", props.ContentClass }\u003e\n\t\t\t{ children... }\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/collapse"
    },
    {
      "name": "countdown",
      "code": "```go\ntype CountdownProps struct {\n\tExpires time.Time\n\tDays    bool\n\tHours   bool\n\tMinutes bool\n\tSeconds bool\n}\n\ntempl Countdown(props CountdownProps) {\n\t{{ spanID := time.Now().UnixNano() }}\n\t\u003cdiv class=\"grid auto-cols-max grid-flow-col gap-5 text-center\"\u003e\n\t\t\u003cdiv\n\t\t\tclass={\n\t\t\t\t\"bg-neutral rounded-box text-neutral-content flex flex-col p-2\",\n\t\t\t\ttempl.KV(\"hidden\", !props.Days),\n\t\t\t}\n\t\t\u003e\n\t\t\t\u003cspan class=\"countdown font-mono text-5xl\"\u003e\n\t\t\t\t\u003cspan id={ fmt.Sprintf(\"span-days-%d\", spanID) } style=\"--value:15;\" aria-live=\"polite\" aria-label=\"15\"\u003e15\u003c/span\u003e\n\t\t\t\u003c/span\u003e\n\t\t\tdays\n\t\t\u003c/div\u003e\n\t\t\u003cdiv\n\t\t\tclass={\n\t\t\t\t\"bg-neutral rounded-box text-neutral-content flex flex-col p-2\",\n\t\t\t\ttempl.KV(\"hidden\", !props.Hours),\n\t\t\t}\n\t\t\u003e\n\t\t\t\u003cspan class=\"countdown font-mono text-5xl\"\u003e\n\t\t\t\t\u003cspan id={ fmt.Sprintf(\"span-hours-%d\", spanID) } style=\"--value:10;\" aria-live=\"polite\" aria-label=\"10\"\u003e10\u003c/span\u003e\n\t\t\t\u003c/span\u003e\n\t\t\thours\n\t\t\u003c/div\u003e\n\t\t\u003cdiv\n\t\t\tclass={\n\t\t\t\t\"bg-neutral rounded-box text-neutral-content flex flex-col p-2\",\n\t\t\t\ttempl.KV(\"hidden\", !props.Minutes),\n\t\t\t}\n\t\t\u003e\n\t\t\t\u003cspan class=\"countdown font-mono text-5xl\"\u003e\n\t\t\t\t\u003cspan id={ fmt.Sprintf(\"span-minutes-%d\", spanID) } style=\"--value:24;\" aria-live=\"polite\" aria-label=\"24\"\u003e24\u003c/span\u003e\n\t\t\t\u003c/span\u003e\n\t\t\tmin\n\t\t\u003c/div\u003e\n\t\t\u003cdiv\n\t\t\tclass={\n\t\t\t\t\"bg-neutral rounded-box text-neutral-content flex flex-col p-2\",\n\t\t\t\ttempl.KV(\"hidden\", !props.Seconds),\n\t\t\t}\n\t\t\u003e\n\t\t\t\u003cspan class=\"countdown font-mono text-5xl\"\u003e\n\t\t\t\t\u003cspan id={ fmt.Sprintf(\"span-seconds-%d\", spanID) } style=\"--value:59;\" aria-live=\"polite\" aria-label=\"59\"\u003e59\u003c/span\u003e\n\t\t\t\u003c/span\u003e\n\t\t\tsec\n\t\t\u003c/div\u003e\n\t\t\u003cscript data-expires={ props.Expires.Format(\"2006-01-02T15:04:05Z\") } data-id={ spanID }\u003e\n            var intervalId = null;\n\n            function updateTimes(expires, days, hours, minutes, seconds) {\n                let expiresDate = Date.parse(expires);\n                let now = new Date()\n                let diffMs = Math.abs(expiresDate - now.getTime());\n                let totalSeconds = diffMs / 1000;\n\n                if (now.getTime() \u003e= expiresDate) {\n                    clearInterval(intervalId);\n                    return\n                }\n\n                const daysRemaining = Math.floor(diffMs / (1000 * 60 * 60 * 24))\n                diffMs -= daysRemaining * (1000 * 60 * 60 *24)\n                days.setAttribute(\"style\", `--value:${daysRemaining};`)\n\n                const hoursRemaining = Math.floor(diffMs / (1000 * 60 * 60));\n                diffMs -= hoursRemaining * (1000 * 60 * 60)\n                hours.setAttribute(\"style\", `--value:${hoursRemaining};`)\n\n                const minutesRemaining = Math.floor(diffMs / (1000 * 60));\n                diffMs -= minutesRemaining * (1000 * 60);\n                minutes.setAttribute(\"style\", `--value:${minutesRemaining};`)\n\n                const secondsRemaining = Math.floor(diffMs / 1000);\n                seconds.setAttribute(\"style\", `--value:${secondsRemaining};`)\n            }\n\n            function startUpdatingTimes(expires, days, hours, minutes, seconds) {\n                updateTimes(expires, days, hours, minutes, seconds);\n                intervalId = setInterval(() =\u003e updateTimes(expires, days, hours, minutes, seconds), 1000);\n            }\n\n            ((expires) =\u003e {\n                let days = document.getElementById(`span-days-${document.currentScript.getAttribute(\"data-id\")}`);\n                let hours = document.getElementById(`span-hours-${document.currentScript.getAttribute(\"data-id\")}`);\n                let minutes = document.getElementById(`span-minutes-${document.currentScript.getAttribute(\"data-id\")}`);\n                let seconds = document.getElementById(`span-seconds-${document.currentScript.getAttribute(\"data-id\")}`);\n                startUpdatingTimes(expires, days, hours, minutes, seconds);\n            })(document.currentScript.getAttribute(\"data-expires\"))\n        \u003c/script\u003e\n\t\u003c/div\u003e\n}\n```"
    },
    {
      "name": "diff",
      "code": "```go\ntype DiffProps struct {\n\tWidth  int\n\tHeight int\n\tImage1 DiffImage\n\tImage2 DiffImage\n}\n\ntype DiffImage struct {\n\tSource string\n\tAlt    string\n}\n\ntempl Diff(props DiffProps) {\n\t\u003cdiv class={ \"diff\", fmt.Sprintf(\"aspect-[%d/%d]\", props.Width, props.Height) }\u003e\n\t\t\u003cdiv class=\"diff-item-1\"\u003e\n\t\t\t\u003cimg alt={ props.Image1.Alt } src={ props.Image1.Source }/\u003e\n\t\t\u003c/div\u003e\n\t\t\u003cdiv class=\"diff-item-2\"\u003e\n\t\t\t\u003cimg alt={ props.Image2.Alt } src={ props.Image2.Source }/\u003e\n\t\t\u003c/div\u003e\n\t\t\u003cdiv class=\"diff-resizer\"\u003e\u003c/div\u003e\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/diff"
    },
    {
      "name": "features",
      "code": "```go\ntype FeaturesProps struct {\n\tTitle    string\n\tFeatures []FeatureProps\n}\n\ntype FeatureProps struct {\n\tIcon        templ.Component\n\tTitle       string\n\tDescription string\n\tURL         string\n}\n\ntempl Features(props FeaturesProps) {\n\t\u003cdiv class=\"py-12 px-4\"\u003e\n\t\t\u003cdiv class=\"max-w-screen-xl mx-auto text-base-content/80\"\u003e\n\t\t\tif props.Title != \"\" {\n\t\t\t\t\u003ch2 class=\"sm:text-4xl text-2xl font-bold text-center mb-16\"\u003e{ props.Title }\u003c/h2\u003e\n\t\t\t}\n\t\t\t\u003cdiv class=\"grid lg:grid-cols-3 md:grid-cols-2 gap-12 max-md:max-w-lg mx-auto\"\u003e\n\t\t\t\tfor _, feature := range props.Features {\n\t\t\t\t\t@Feature(feature)\n\t\t\t\t}\n\t\t\t\u003c/div\u003e\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n\ntempl Feature(feature FeatureProps) {\n\t\u003cdiv\n\t\tclass={\n\t\t\t\"flex flex-col justify-between items-center rounded-box group p-8 text-center\",\n\t\t\t\"hover:bg-base-300 hover:text-base-content hover:shadow-xl transition-all duration-300\",\n\t\t}\n\t\u003e\n\t\t@feature.Icon\n\t\tif feature.Title != \"\" {\n\t\t\t\u003ch3 class=\"text-xl font-semibold mb-3\"\u003e{ feature.Title }\u003c/h3\u003e\n\t\t}\n\t\t\u003cp class=\"text-base-content/70 group-hover:text-base-content text-sm\"\u003e{ feature.Description }\u003c/p\u003e\n\t\tif feature.URL != \"\" {\n\t\t\t\u003ca href={ templ.SafeURL(feature.URL) } class=\"mt-2 link link-primary\"\u003eLearn more\u003c/a\u003e\n\t\t}\n\t\u003c/div\u003e\n}\n```"
    },
    {
      "name": "hover_3d_card",
      "code": "```go\ntempl Hover3DCard() {\n\t\u003cdiv class=\"hover-3d\"\u003e\n\t\t{ children... }\n\t\t\u003cdiv\u003e\u003c/div\u003e\n\t\t\u003cdiv\u003e\u003c/div\u003e\n\t\t\u003cdiv\u003e\u003c/div\u003e\n\t\t\u003cdiv\u003e\u003c/div\u003e\n\t\t\u003cdiv\u003e\u003c/div\u003e\n\t\t\u003cdiv\u003e\u003c/div\u003e\n\t\t\u003cdiv\u003e\u003c/div\u003e\n\t\t\u003cdiv\u003e\u003c/div\u003e\n\t\u003c/div\u003e\n}\n```"
    },
    {
      "name": "infinite_scroll",
      "code": "```go\ntempl InfiniteScrollTable(rows []templ.Component) {\n\t@Table(\n\t\t[]templ.Component{PlainText(\"Name\"), PlainText(\"Email\")},\n\t\trows,\n\t\tnil,\n\t)\n\t\u003cdiv class=\"flex justify-center\"\u003e\u003cspan id=\"spinner\" class=\"htmx-indicator loading loading-spinner\"\u003e\u003c/span\u003e\u003c/div\u003e\n}\n\ntempl InfiniteScrollRows(rows []templ.Component) {\n\tfor _, r := range rows {\n\t\t@r\n\t}\n}\n\ntempl InfiniteScrollRow(name, email string, page int, hasMore bool) {\n\t\u003ctr\n\t\tif hasMore {\n\t\t\thx-get={ fmt.Sprintf(\"/infinite-scroll-rows?page=%d\", page+1) }\n\t\t\thx-target=\"this\"\n\t\t\thx-trigger=\"intersect once\"\n\t\t\thx-swap=\"afterend\"\n\t\t\thx-indicator=\"#spinner\"\n\t\t}\n\t\u003e\n\t\t\u003ctd\u003e{ name }\u003c/td\u003e\n\t\t\u003ctd\u003e{ email }\u003c/td\u003e\n\t\u003c/tr\u003e\n}\n```"
    },
    {
      "name": "lazy_load",
      "code": "```go\ntempl LazyLoad(url string) {\n\t\u003cdiv\n\t\thx-get={ url }\n\t\thx-trigger=\"load\"\n\t\thx-target=\"this\"\n\t\tclass=\"flex justify-center items-center py-8\"\n\t\u003e\n\t\t\u003cspan class=\"loading loading-spinner\"\u003e\u003c/span\u003e\n\t\u003c/div\u003e\n}\n```"
    },
    {
      "name": "pricing",
      "code": "```go\ntype PricingProps struct {\n\tChecked bool\n\tPrices  []PriceProps\n}\n\ntype PriceProps struct {\n\tTitle            string\n\tDescription      string\n\tPriceMonthly     string\n\tPerMonthly       string\n\tPriceAnnually    string\n\tPerAnnually      string\n\tPerUser          bool\n\tPromotion        string\n\tIncludedFeatures []string\n\tExcludedFeatures []string\n\tCallToAction     PriceButtonProps\n\tFooter           templ.Component\n}\n\ntype PriceButtonProps struct {\n\tLabel string\n\tAttrs templ.Attributes\n}\n\n// NOTE: Requires Alpine.js\ntempl Pricing(props PricingProps) {\n\t\u003cscript src=\"/static/js/alpine.js\" defer\u003e\u003c/script\u003e\n\t\u003cdiv x-data=\"{ yearly: true }\" class=\"w-full mx-auto py-8 max-w-screen-xl\"\u003e\n\t\t\u003cdiv class=\"max-w-xs mx-auto my-6\"\u003e\n\t\t\t@Toggle(ToggleProps{\n\t\t\t\tBefore:    \"Billed monthly\",\n\t\t\t\tAfter:     \"Billed annually\",\n\t\t\t\tName:      \"period\",\n\t\t\t\tChecked:   props.Checked,\n\t\t\t\tHighlight: true,\n\t\t\t\tAttrs: templ.Attributes{\n\t\t\t\t\t\"x-on:click\": \"yearly = !yearly\",\n\t\t\t\t},\n\t\t\t})\n\t\t\u003c/div\u003e\n\t\t@PriceGrid(props.Prices)\n\t\u003c/div\u003e\n}\n\ntempl PriceGrid(prices []PriceProps) {\n\t\u003cdiv\n\t\tid=\"price-grid\"\n\t\tclass={ \"grid auto-cols-fr grid-flow-row lg:grid-flow-col pt-4 w-full mx-auto gap-4\",\n            templ.KV(\"gap-8\", slices.ContainsFunc(prices, func(pp PriceProps) bool {\n                    return pp.Promotion != \"\"\n                })) }\n\t\u003e\n\t\tfor i := range prices {\n\t\t\t@Price(prices[i], nil)\n\t\t}\n\t\u003c/div\u003e\n}\n\ntempl Price(price PriceProps, footer templ.Component) {\n\t\u003cdiv class={ \"relative\", templ.KV(\"scale-110\", price.Promotion != \"\") }\u003e\n\t\t\u003cdiv\n\t\t\tclass={\n\t\t\t\t\"card rounded-box w-full max-w-xs p-6 mx-auto shadow-xl shadow-base-300\",\n\t\t\t\t\"bg-gradient-to-br from-base-200 dark:from-base-300 via-base-100 to-base-200 dark:to-base-300\",\n\t\t\t\ttempl.KV(\"ring-base-content/60\", price.Promotion == \"\"),\n\t\t\t\ttempl.KV(\"ring-1 ring-accent\", price.Promotion != \"\"),\n\t\t\t}\n\t\t\u003e\n\t\t\tif price.Promotion != \"\" {\n\t\t\t\t\u003cspan class=\"absolute top-0 right-0 bg-accent px-2 rounded-tr-box rounded-bl-box\"\u003e\n\t\t\t\t\t{ price.Promotion }\n\t\t\t\t\u003c/span\u003e\n\t\t\t}\n\t\t\t\u003cdiv class=\"card-title text-2xl mt-8\"\u003e\n\t\t\t\t\u003ch2 class=\"mx-auto\"\u003e{ price.Title }\u003c/h2\u003e\n\t\t\t\u003c/div\u003e\n\t\t\t\u003cp x-show=\"yearly\" class=\"text-center text-3xl font-bold mt-8\"\u003e\n\t\t\t\t{ price.PriceAnnually }\n\t\t\t\t\u003cspan class=\"text-xs font-normal\"\u003e\n\t\t\t\t\t{ price.PerAnnually }\n\t\t\t\t\u003c/span\u003e\n\t\t\t\tif price.PerUser {\n\t\t\t\t\t\u003cspan class=\"text-sm font-normal\"\u003e\n\t\t\t\t\t\t{ \" / user\" }\n\t\t\t\t\t\u003c/span\u003e\n\t\t\t\t}\n\t\t\t\u003c/p\u003e\n\t\t\t\u003cp x-show=\"!yearly\" class=\"text-center text-3xl font-bold mt-8\"\u003e\n\t\t\t\t{ price.PriceMonthly } \u003cspan class=\"text-xs font-normal\"\u003e{ price.PerMonthly }\u003c/span\u003e\n\t\t\t\u003c/p\u003e\n\t\t\t\u003cbutton { price.CallToAction.Attrs... }\u003e\n\t\t\t\t{ price.CallToAction.Label }\n\t\t\t\u003c/button\u003e\n\t\t\t\u003cdiv class=\"text-sm mt-8\"\u003e\n\t\t\t\t\u003cul class=\"space-y-4\"\u003e\n\t\t\t\t\tfor i := range price.IncludedFeatures {\n\t\t\t\t\t\t\u003cli class=\"flex items-center space-x-2\"\u003e\n\t\t\t\t\t\t\t\u003csvg class=\"w-4 h-4\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\"\u003e\n\t\t\t\t\t\t\t\t\u003cpath class=\"fill-base-content\" fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M21.5821 5.54289C21.9726 5.93342 21.9726 6.56658 21.5821 6.95711L10.2526 18.2867C9.86452 18.6747 9.23627 18.6775 8.84475 18.293L2.29929 11.8644C1.90527 11.4774 1.89956 10.8443 2.28655 10.4503C2.67354 10.0562 3.30668 10.0505 3.70071 10.4375L9.53911 16.1717L20.1679 5.54289C20.5584 5.15237 21.1916 5.15237 21.5821 5.54289Z\"\u003e\u003c/path\u003e\n\t\t\t\t\t\t\t\u003c/svg\u003e\n\t\t\t\t\t\t\t\u003cspan\u003e{ price.IncludedFeatures[i] }\u003c/span\u003e\n\t\t\t\t\t\t\u003c/li\u003e\n\t\t\t\t\t}\n\t\t\t\t\u003c/ul\u003e\n\t\t\t\tif len(price.ExcludedFeatures) \u003e 0 {\n\t\t\t\t\t\u003cdiv class=\"divider !my-2\"\u003e\u003c/div\u003e\n\t\t\t\t}\n\t\t\t\t\u003cul class=\"space-y-4\"\u003e\n\t\t\t\t\tfor i := range price.ExcludedFeatures {\n\t\t\t\t\t\t\u003cli class=\"flex items-center space-x-2 pl-6\"\u003e\n\t\t\t\t\t\t\t\u003cspan class=\"text-base-content/50\"\u003e{ price.ExcludedFeatures[i] }\u003c/span\u003e\n\t\t\t\t\t\t\u003c/li\u003e\n\t\t\t\t\t}\n\t\t\t\t\u003c/ul\u003e\n\t\t\t\u003c/div\u003e\n\t\t\tif footer != nil {\n\t\t\t\t@footer\n\t\t\t}\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n```"
    },
    {
      "name": "stats",
      "code": "```go\ntype StatProps struct {\n\tTitle       string\n\tValue       string\n\tDescription string\n}\n\ntempl Stats() {\n\t\u003cdiv class=\"stats stats-horizontal shadow-sm\"\u003e\n\t\t{ children... }\n\t\u003c/div\u003e\n}\n\ntempl Stat(props StatProps) {\n\t\u003cdiv class=\"stat\"\u003e\n\t\t\u003cdiv class=\"stat-title\"\u003e{ props.Title }\u003c/div\u003e\n\t\t\u003cdiv class=\"stat-value\"\u003e{ props.Value }\u003c/div\u003e\n\t\tif props.Description != \"\" {\n\t\t\t\u003cdiv class=\"stat-desc\"\u003e{ props.Description }\u003c/div\u003e\n\t\t}\n\t\t\u003cdiv class=\"stat-actions\"\u003e\n\t\t\t{ children... }\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/stat"
    },
    {
      "name": "table",
      "code": "```go\ntempl Table(headers []templ.Component, rows []templ.Component, attrs templ.Attributes) {\n\t\u003cdiv class=\"overflow-x-auto\"\u003e\n\t\t\u003ctable { attrs... } class=\"table\"\u003e\n\t\t\t\u003cthead\u003e\n\t\t\t\t\u003ctr\u003e\n\t\t\t\t\tfor _, header := range headers {\n\t\t\t\t\t\t\u003cth\u003e\n\t\t\t\t\t\t\t@header\n\t\t\t\t\t\t\u003c/th\u003e\n\t\t\t\t\t}\n\t\t\t\t\u003c/tr\u003e\n\t\t\t\u003c/thead\u003e\n\t\t\t\u003ctbody\u003e\n\t\t\t\tfor _, trow := range rows {\n\t\t\t\t\t@trow\n\t\t\t\t}\n\t\t\t\u003c/tbody\u003e\n\t\t\u003c/table\u003e\n\t\u003c/div\u003e\n}\n\n// Component to use as plain text when\n// templ.Component is used as argument\ntempl PlainText(content string) {\n\t{ content }\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/table"
    },
    {
      "name": "testimonial",
      "code": "```go\ntype TestimonialProps []TestimonialProp\n\ntype TestimonialProp struct {\n\tAvatar  templ.Component\n\tName    string\n\tRating  int\n\tContent string\n}\n\ntempl TestimonialGrid(title string, props TestimonialProps) {\n\t\u003csection\u003e\n\t\t\u003cdiv class=\"mx-auto max-w-screen-xl px-4 py-12 sm:px-6 lg:px-8 lg:py-16\"\u003e\n\t\t\t\u003ch2 class=\"text-center text-4xl font-bold tracking-tight sm:text-5xl\"\u003e\n\t\t\t\t{ title }\n\t\t\t\u003c/h2\u003e\n\t\t\t\u003cdiv class=\"mt-8 [column-fill:_balance] sm:columns-2 sm:gap-6 lg:columns-3 lg:gap-8\"\u003e\n\t\t\t\tfor i := range props {\n\t\t\t\t\t\u003cdiv class=\"mb-8 sm:break-inside-avoid\"\u003e\n\t\t\t\t\t\t\u003cblockquote class=\"rounded-lg bg-base-300 p-6 shadow-sm sm:p-8\"\u003e\n\t\t\t\t\t\t\t\u003cdiv class=\"flex items-center gap-4\"\u003e\n\t\t\t\t\t\t\t\tif props[i].Avatar != nil {\n\t\t\t\t\t\t\t\t\t@props[i].Avatar\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\u003cdiv\u003e\n\t\t\t\t\t\t\t\t\t@RatingDisplay(RatingProps{\n\t\t\t\t\t\t\t\t\t\tName:  fmt.Sprintf(\"review-rating-%d\", i),\n\t\t\t\t\t\t\t\t\t\tMin:   1,\n\t\t\t\t\t\t\t\t\t\tMax:   5,\n\t\t\t\t\t\t\t\t\t\tValue: props[i].Rating,\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\u003cp class=\"mt-0.5 text-lg font-medium\"\u003e{ props[i].Name }\u003c/p\u003e\n\t\t\t\t\t\t\t\t\u003c/div\u003e\n\t\t\t\t\t\t\t\u003c/div\u003e\n\t\t\t\t\t\t\t\u003cp class=\"mt-4\"\u003e\n\t\t\t\t\t\t\t\t{ props[i].Content }\n\t\t\t\t\t\t\t\u003c/p\u003e\n\t\t\t\t\t\t\u003c/blockquote\u003e\n\t\t\t\t\t\u003c/div\u003e\n\t\t\t\t}\n\t\t\t\u003c/div\u003e\n\t\t\u003c/div\u003e\n\t\u003c/section\u003e\n}\n```"
    },
    {
      "name": "text_rotate",
      "code": "```go\ntype TextRotateProps struct {\n\tClass string\n\tItems []TextRotateItem\n}\n\ntype TextRotateItem struct {\n\tText  string\n\tClass string\n}\n\ntempl TextRotate(props TextRotateProps) {\n\t\u003cspan class={ \"text-rotate\", props.Class }\u003e\n\t\t\u003cspan\u003e\n\t\t\tfor _, item := range props.Items {\n\t\t\t\t\u003cspan class={ item.Class }\u003e{ item.Text }\u003c/span\u003e\n\t\t\t}\n\t\t\u003c/span\u003e\n\t\u003c/span\u003e\n}\n```"
    },
    {
      "name": "timeline",
      "code": "```go\ntype TimelineProps []TimelineProp\n\ntype TimelineProp struct {\n\tStart  string\n\tMiddle templ.Component\n\tEnd    string\n}\n\ntempl Timeline(props TimelineProps) {\n\t\u003cul class=\"timeline\"\u003e\n\t\tfor i, prop := range props {\n\t\t\t\u003cli\u003e\n\t\t\t\tif i \u003e 0 {\n\t\t\t\t\t\u003chr/\u003e\n\t\t\t\t}\n\t\t\t\tif prop.Start != \"\" {\n\t\t\t\t\t\u003cdiv class=\"timeline-start\"\u003e{ prop.Start }\u003c/div\u003e\n\t\t\t\t}\n\t\t\t\tif prop.Middle != nil {\n\t\t\t\t\t\u003cdiv class=\"timeline-middle\"\u003e\n\t\t\t\t\t\t@prop.Middle\n\t\t\t\t\t\u003c/div\u003e\n\t\t\t\t}\n\t\t\t\tif prop.End != \"\" {\n\t\t\t\t\t\u003cdiv class=\"timeline-end\"\u003e{ prop.End }\u003c/div\u003e\n\t\t\t\t}\n\t\t\t\tif i \u003c len(props) - 1 {\n\t\t\t\t\t\u003chr/\u003e\n\t\t\t\t}\n\t\t\t\u003c/li\u003e\n\t\t}\n\t\u003c/ul\u003e\n}\n\ntempl TimelineCheckbox(checked bool) {\n\t\u003csvg\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\tviewBox=\"0 0 20 20\"\n\t\tfill=\"currentColor\"\n\t\tclass={ \"h-5 w-5\", templ.KV(\"fill-primary\", checked) }\n\t\u003e\n\t\t\u003cpath\n\t\t\tfill-rule=\"evenodd\"\n\t\t\td=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\n\t\t\tclip-rule=\"evenodd\"\n\t\t\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/timeline"
    }
  ],
  "data_input": [
    {
      "name": "checkbox",
      "code": "```go\ntype CheckboxProps struct {\n\tID      string\n\tBefore  string\n\tAfter   string\n\tName    string\n\tChecked bool\n\tClass   string\n\tAttrs   templ.Attributes\n\tSize    string\n}\n\ntempl Checkbox(props CheckboxProps) {\n\t\u003clabel class=\"label justify-center cursor-pointer\"\u003e\n\t\tif props.Before != \"\" {\n\t\t\t\u003cspan\n\t\t\t\tclass={\n\t\t\t\t\ttempl.KV(\"text-xs\", props.Size == \"xs\"),\n\t\t\t\t\ttempl.KV(\"text-sm\", props.Size == \"sm\"),\n\t\t\t\t\ttempl.KV(\"text-lg\", props.Size == \"lg\"),\n\t\t\t\t\ttempl.KV(\"text-xl\", props.Size == \"xl\"),\n\t\t\t\t\t\"mr-2\",\n\t\t\t\t}\n\t\t\t\u003e\n\t\t\t\t{ props.Before }\n\t\t\t\u003c/span\u003e\n\t\t}\n\t\t\u003cinput\n\t\t\t{ props.Attrs... }\n\t\t\tif props.ID != \"\" {\n\t\t\t\tid={ props.ID }\n\t\t\t}\n\t\t\ttype=\"checkbox\"\n\t\t\tname={ props.Name }\n\t\t\tif props.Checked {\n\t\t\t\tchecked=\"checked\"\n\t\t\t}\n\t\t\tclass={\n\t\t\t\t\"checkbox\", props.Class,\n\t\t\t\ttempl.KV(\"checkbox-xs\", props.Size == \"xs\"),\n\t\t\t\ttempl.KV(\"checkbox-sm\", props.Size == \"sm\"),\n\t\t\t\ttempl.KV(\"checkbox-lg\", props.Size == \"lg\"),\n\t\t\t\ttempl.KV(\"checkbox-xl\", props.Size == \"xl\"),\n\t\t\t}\n\t\t/\u003e\n\t\tif props.After != \"\" {\n\t\t\t\u003cspan class=\"ml-2\"\u003e\n\t\t\t\t{ props.After }\n\t\t\t\u003c/span\u003e\n\t\t}\n\t\u003c/label\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/checkbox"
    },
    {
      "name": "combobox",
      "code": "```go\ntype ComboboxProps struct {\n\tLabel    string\n\tName     string\n\tURL      string\n\tOptions  []string\n\tSelected []string\n}\n\ntempl Combobox(props ComboboxProps) {\n\t\u003cdetails class=\"dropdown w-full max-w-md min-h-8\"\u003e\n\t\t\u003csummary\n\t\t\tclass={\n\t\t\t\t\"cursor-pointer flex space-x-2 w-full rounded-box\",\n\t\t\t\t\"border border-base-content py-1 px-2\",\n\t\t\t}\n\t\t\u003e\n\t\t\t\u003cspan class=\"text-sm text-nowrap\"\u003e{ props.Label }\u003c/span\u003e\n\t\t\t\u003cdiv class=\"w-full flex items-center space-x-1\"\u003e\n\t\t\t\t\u003cdiv\n\t\t\t\t\tid={ fmt.Sprintf(\"%s_selections\", props.Name) }\n\t\t\t\t\tclass=\"w-full grid-flow-col-dense\"\n\t\t\t\t\u003e\n\t\t\t\t\tfor _, s := range props.Selected {\n\t\t\t\t\t\t@ComboBadge(props.Name, s)\n\t\t\t\t\t}\n\t\t\t\t\u003c/div\u003e\n\t\t\t\u003c/div\u003e\n\t\t\u003c/summary\u003e\n\t\t\u003cul class=\"menu dropdown-content bg-base-200 rounded-box z-50 p-2 shadow-sm\"\u003e\n\t\t\tfor _, opt := range props.Options {\n\t\t\t\t\u003cli\u003e\n\t\t\t\t\t\u003clabel class=\"label cursor-pointer space-x-2\"\u003e\n\t\t\t\t\t\t\u003cspan class=\"label-text\"\u003e\n\t\t\t\t\t\t\t{ opt }\n\t\t\t\t\t\t\u003c/span\u003e\n\t\t\t\t\t\t\u003cinput\n\t\t\t\t\t\t\thx-post={ fmt.Sprintf(props.URL, props.Name, url.PathEscape(opt)) }\n\t\t\t\t\t\t\thx-target={ fmt.Sprintf(\"#%s_selections\", props.Name) }\n\t\t\t\t\t\t\thx-swap=\"beforeend\"\n\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\tname={ props.Name }\n\t\t\t\t\t\t\tclass={ \"checkbox\" }\n\t\t\t\t\t\t/\u003e\n\t\t\t\t\t\u003c/label\u003e\n\t\t\t\t\u003c/li\u003e\n\t\t\t}\n\t\t\u003c/ul\u003e\n\t\t\u003cscript data-checkbox-name={ props.Name } type=\"text/javascript\"\u003e\n\t\t\tvar name = document.currentScript.getAttribute(\"data-checkbox-name\");\n\t\t\t((name) =\u003e {\n\t\t\t\tdocument.addEventListener(\"htmx:configRequest\", (evt) =\u003e {\n\t\t\t\t\tif (evt.target.getAttribute(\"name\") === name \u0026\u0026 !evt.target.checked) {\n\t\t\t\t\t\t// prevent htmx request when checkbox is unchecked\n\t\t\t\t\t\tevt.preventDefault()\n\n\t\t\t\t\t\t// remove from selected elements\n\t\t\t\t\t\tlet label = evt.target.closest(\"label\")\n\t\t\t\t\t\tif (label !== null \u0026\u0026 label !== undefined) {\n\t\t\t\t\t\t\tlet span = label.querySelector(\"span.label-text\")\n\t\t\t\t\t\t\tlet value = span.innerText\n\t\t\t\t\t\t\tlet input = document.querySelector(`input[value=\"${value}\"]`)\n\t\t\t\t\t\t\tif (input.getAttribute(\"name\") === name) {\n\t\t\t\t\t\t\t\tinput.closest(\"div\").remove()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})(name);\n\t\t\u003c/script\u003e\n\t\u003c/details\u003e\n}\n\ntempl ComboBadge(name, value string) {\n\t\u003cdiv class=\"ml-2 badge badge-neutral p-1 text-nowrap select-none\"\u003e\n\t\t\u003cinput type=\"hidden\" name={ name } value={ value }/\u003e\n\t\t\u003cspan\u003e{ value }\u003c/span\u003e\n\t\t\u003cbutton\n\t\t\tonclick=\"uncheckAndRemoveBadge(event)\"\n\t\t\tclass=\"ml-1 btn btn-xs btn-circle btn-ghost\"\n\t\t\u003e\n\t\t\t@crossIcon()\n\t\t\u003c/button\u003e\n\t\t\u003cscript\u003e\n\t\t\tfunction uncheckAndRemoveBadge(evt) {\n\t\t\t\tvar div = evt.target.parentElement\n\t\t\t\twhile (div.nodeName !== \"DIV\") {\n\t\t\t\t\tdiv = div.parentElement\n\t\t\t\t}\n\t\t\t\tlet input = div.querySelector(\"input[type=hidden]\")\n\t\t\t\tlet name = input.getAttribute(\"name\")\n\t\t\t\tlet labelText = input.value\n\n\t\t\t\tlet details = div.closest(\"details\")\n\t\t\t\tlet ul = details.querySelector(\"ul\")\n\t\t\t\tlet checkboxes = ul.querySelectorAll(`input[name=\"${name}\"]`)\n\t\t\t\tcheckboxes.forEach((cb) =\u003e {\n\t\t\t\t\tif (cb.checked) {\n\t\t\t\t\t\tlet label = cb.parentElement\n\t\t\t\t\t\tlabel.querySelectorAll(\"span.label-text\").forEach((el) =\u003e {\n\t\t\t\t\t\t\tif (el.innerHTML === labelText) {\n\t\t\t\t\t\t\t\tcb.checked = false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\tdiv.remove()\n\t\t\t}\n\t\t\u003c/script\u003e\n\t\u003c/div\u003e\n}\n\ntempl crossIcon() {\n\t\u003csvg\n\t\tclass=\"h-3 w-3\"\n\t\tviewBox=\"0 0 25 25\"\n\t\tversion=\"1.1\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\txmlns:xlink=\"http://www.w3.org/1999/xlink\"\n\t\txmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\"\n\t\u003e\n\t\t\u003cg stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\"\u003e\n\t\t\t\u003cg class=\"fill-base-content\" id=\"Icon-Set-Filled\" sketch:type=\"MSLayerGroup\" transform=\"translate(-469.000000, -1041.000000)\"\u003e\n\t\t\t\t\u003cpath d=\"M487.148,1053.48 L492.813,1047.82 C494.376,1046.26 494.376,1043.72 492.813,1042.16 C491.248,1040.59 488.712,1040.59 487.148,1042.16 L481.484,1047.82 L475.82,1042.16 C474.257,1040.59 471.721,1040.59 470.156,1042.16 C468.593,1043.72 468.593,1046.26 470.156,1047.82 L475.82,1053.48 L470.156,1059.15 C468.593,1060.71 468.593,1063.25 470.156,1064.81 C471.721,1066.38 474.257,1066.38 475.82,1064.81 L481.484,1059.15 L487.148,1064.81 C488.712,1066.38 491.248,1066.38 492.813,1064.81 C494.376,1063.25 494.376,1060.71 492.813,1059.15 L487.148,1053.48\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n\t\t\t\u003c/g\u003e\n\t\t\u003c/g\u003e\n\t\u003c/svg\u003e\n}\n```"
    },
    {
      "name": "date_picker",
      "code": "```go\ntype DatePickerProps struct {\n\tYear        int\n\tMonth       int\n\tSelected    time.Time\n\tStartOfWeek time.Weekday\n}\n\nfunc (props DatePickerProps) Days() []time.Time {\n\tdays := make([]time.Time, 0, 31)\n\tnow := time.Now().UTC()\n\tstart := time.Date(props.Year, time.Month(props.Month), 1, 0, 0, 0, 0, now.Location())\n\tend := start.AddDate(0, 1, -1)\n\tfor end.Weekday() != props.StartOfWeek {\n\t\tend = end.AddDate(0, 0, 1)\n\t}\n\tend = end.AddDate(0, 0, -1)\n\n\tfor start.Weekday() != props.StartOfWeek {\n\t\tstart = start.AddDate(0, 0, -1)\n\t}\n\tfor !start.After(end) {\n\t\tdays = append(days, start)\n\t\tstart = start.AddDate(0, 0, 1)\n\t}\n\treturn days\n}\n\nfunc (props DatePickerProps) Months() []time.Time {\n\tmonths := make([]time.Time, 12)\n\tfor i := 1; i \u003c= 12; i++ {\n\t\tdt := time.Date(props.Year, time.Month(i), 1, 0, 0, 0, 0, time.Now().Location())\n\t\tmonths[i-1] = dt\n\t}\n\treturn months\n}\n\ntempl DatePicker(props DatePickerProps) {\n\t{{ utcNow := time.Now().UTC() }}\n\t{{ days := props.Days() }}\n\t\u003cdiv\n\t\tname=\"datepicker-div\"\n\t\tclass=\"flex flex-col space-y-1 w-[300px] h-[405px]\"\n\t\u003e\n\t\t\u003cdiv class=\"flex space-x-1\"\u003e\n\t\t\t\u003cbutton\n\t\t\t\thx-get={ fmt.Sprintf(\"/datepicker?year=%d\u0026month=%d\", props.Year, props.Month-1) }\n\t\t\t\thx-target=\"div[name=datepicker-div]\"\n\t\t\t\thx-swap=\"outerHTML\"\n\t\t\t\tclass=\"btn btn-square btn-sm\"\n\t\t\t\u003e\n\t\t\t\t\u003csvg class=\"h-3 w-3\" viewBox=\"-5.5 0 26 26\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\"\u003e\n\t\t\t\t\t\u003cg id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\"\u003e\n\t\t\t\t\t\t\u003cg class=\"fill-base-content\" id=\"Icon-Set-Filled\" sketch:type=\"MSLayerGroup\" transform=\"translate(-423.000000, -1196.000000)\"\u003e\n\t\t\t\t\t\t\t\u003cpath d=\"M428.115,1209 L437.371,1200.6 C438.202,1199.77 438.202,1198.43 437.371,1197.6 C436.541,1196.76 435.194,1196.76 434.363,1197.6 L423.596,1207.36 C423.146,1207.81 422.948,1208.41 422.985,1209 C422.948,1209.59 423.146,1210.19 423.596,1210.64 L434.363,1220.4 C435.194,1221.24 436.541,1221.24 437.371,1220.4 C438.202,1219.57 438.202,1218.23 437.371,1217.4 L428.115,1209\" id=\"chevron-left\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n\t\t\t\t\t\t\u003c/g\u003e\n\t\t\t\t\t\u003c/g\u003e\n\t\t\t\t\u003c/svg\u003e\n\t\t\t\u003c/button\u003e\n\t\t\t\u003cdetails class=\"dropdown w-full max-w-[300px]\"\u003e\n\t\t\t\t\u003csummary class=\"btn btn-sm w-full\"\u003e{ fmt.Sprintf(\"%d\", props.Year) }\u003c/summary\u003e\n\t\t\t\t\u003cdiv\n\t\t\t\t\tclass={\n\t\t\t\t\t\t\"menu dropdown-content grid grid-cols-3 gap-1\",\n\t\t\t\t\t\t\"w-full max-w-[300px] p-1 bg-base-300 rounded-b-box\",\n\t\t\t\t\t}\n\t\t\t\t\thx-get={ fmt.Sprintf(\"/datepicker/yearpicker?year=%d\", props.Year) }\n\t\t\t\t\thx-trigger=\"datePickerDropdownClosed from:body\"\n\t\t\t\t\u003e\n\t\t\t\t\t@DatePickerYearPicker(props)\n\t\t\t\t\u003c/div\u003e\n\t\t\t\t\u003cscript\u003e\n                    ((details)=\u003e{\n                        details.querySelector(\"summary\").addEventListener(\"click\", (evt) =\u003e {\n                            if (details.hasAttribute(\"open\")) {\n                                    let event = new Event(\"datePickerDropdownClosed\");\n                                    document.querySelector(\"body\").dispatchEvent(event);\n                                }\n                        })\n                    })(document.currentScript.parentElement)\n                \u003c/script\u003e\n\t\t\t\u003c/details\u003e\n\t\t\t\u003cbutton\n\t\t\t\thx-get={ fmt.Sprintf(\"/datepicker?year=%d\u0026month=%d\", props.Year, props.Month+1) }\n\t\t\t\thx-target=\"div[name=datepicker-div]\"\n\t\t\t\thx-swap=\"outerHTML\"\n\t\t\t\tclass=\"btn btn-square btn-sm\"\n\t\t\t\u003e\n\t\t\t\t\u003csvg class=\"h-3 w-3\" viewBox=\"-5.5 0 26 26\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\"\u003e\n\t\t\t\t\t\u003cg id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\"\u003e\n\t\t\t\t\t\t\u003cg class=\"fill-base-content\" id=\"Icon-Set-Filled\" sketch:type=\"MSLayerGroup\" transform=\"translate(-474.000000, -1196.000000)\"\u003e\n\t\t\t\t\t\t\t\u003cpath d=\"M488.404,1207.36 L477.637,1197.6 C476.806,1196.76 475.459,1196.76 474.629,1197.6 C473.798,1198.43 473.798,1199.77 474.629,1200.6 L483.885,1209 L474.629,1217.4 C473.798,1218.23 473.798,1219.57 474.629,1220.4 C475.459,1221.24 476.806,1221.24 477.637,1220.4 L488.404,1210.64 C488.854,1210.19 489.052,1209.59 489.015,1209 C489.052,1208.41 488.854,1207.81 488.404,1207.36\" id=\"chevron-right\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n\t\t\t\t\t\t\u003c/g\u003e\n\t\t\t\t\t\u003c/g\u003e\n\t\t\t\t\u003c/svg\u003e\n\t\t\t\u003c/button\u003e\n\t\t\u003c/div\u003e\n\t\t\u003cdiv class=\"grid grid-cols-7 gap-1 text-sm text-base-content/75\"\u003e\n\t\t\tif props.StartOfWeek == time.Sunday {\n\t\t\t\t\u003cspan class=\"text-center\"\u003eSu\u003c/span\u003e\n\t\t\t}\n\t\t\t\u003cspan class=\"text-center\"\u003eMo\u003c/span\u003e\n\t\t\t\u003cspan class=\"text-center\"\u003eTu\u003c/span\u003e\n\t\t\t\u003cspan class=\"text-center\"\u003eWe\u003c/span\u003e\n\t\t\t\u003cspan class=\"text-center\"\u003eTh\u003c/span\u003e\n\t\t\t\u003cspan class=\"text-center\"\u003eFr\u003c/span\u003e\n\t\t\t\u003cspan class=\"text-center\"\u003eSa\u003c/span\u003e\n\t\t\tif props.StartOfWeek == time.Monday {\n\t\t\t\t\u003cspan class=\"text-center\"\u003eSu\u003c/span\u003e\n\t\t\t}\n\t\t\u003c/div\u003e\n\t\t\u003cdiv\n\t\t\tclass=\"grid grid-cols-7 gap-1\"\n\t\t\u003e\n\t\t\t@DatePickerInput(props.Selected)\n\t\t\tfor _, d := range days {\n\t\t\t\t\u003cbutton\n\t\t\t\t\tname=\"datepicker-day-btn\"\n\t\t\t\t\tclass={\n\t\t\t\t\t\t\"btn btn-square border shadow-md shadow-base-300 h-10 w-10 p-3\",\n\t\t\t\t\t\ttempl.KV(\"text-primary\", d.Year() == utcNow.Year() \u0026\u0026 d.Month() == utcNow.Month() \u0026\u0026 utcNow.Day() == d.Day()),\n\t\t\t\t\t\ttempl.KV(\"btn-ghost\", d.Month() == time.Month(props.Month)),\n\t\t\t\t\t\ttempl.KV(\"btn-neutral\", d.Month() != time.Month(props.Month)),\n\t\t\t\t\t\ttempl.KV(\"border-primary bg-base-300\", !props.Selected.IsZero() \u0026\u0026 d.Day() == props.Selected.Day()),\n\t\t\t\t\t}\n\t\t\t\t\thx-post={ \"/datepicker/select?date=\" + d.Format(\"2006-01-02\") }\n\t\t\t\t\thx-target=\"#datepicker-input\"\n\t\t\t\t\thx-swap=\"outerHTML\"\n\t\t\t\t\tif d.Month() != time.Month(props.Month) {\n\t\t\t\t\t\tdisabled\n\t\t\t\t\t}\n\t\t\t\t\u003e\n\t\t\t\t\tif d.Day() == 1 {\n\t\t\t\t\t\t{ d.Format(\"Jan \") }\n\t\t\t\t\t}\n\t\t\t\t\t{ d.Format(\"2\") }\n\t\t\t\t\u003c/button\u003e\n\t\t\t}\n\t\t\t\u003cscript\u003e\n                function addDayButtonEventHandler() {\n                    document.querySelectorAll(\"button[name=datepicker-day-btn]\").forEach((btn) =\u003e {\n                        btn.addEventListener(\"click\", () =\u003e {\n                            document.querySelectorAll(\"button[name=datepicker-day-btn]\").forEach((el) =\u003e {\n                                el.classList.remove(\"border-primary\", \"bg-base-300\")\n                            })\n                            btn.classList.add(\"border-primary\", \"bg-base-300\")\n                        })\n                    })\n                }\n                document.addEventListener(\"htmx:afterSettle\", () =\u003e {\n                    addDayButtonEventHandler();\n                })\n                document.addEventListener(\"DOMContentLoaded\", () =\u003e {\n                    addDayButtonEventHandler();\n                })\n            \u003c/script\u003e\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n\ntempl DatePickerInput(d time.Time) {\n\t\u003cinput id=\"datepicker-input\" type=\"hidden\" name=\"date\" value={ d.Format(\"2006-01-02\") }/\u003e\n}\n\ntempl DatePickerYearPicker(props DatePickerProps) {\n\t{{ utcNow := time.Now().UTC() }}\n\tfor i := range 12 {\n\t\t\u003cbutton\n\t\t\tclass=\"btn btn-sm border\"\n\t\t\thx-get={ fmt.Sprintf(\"/datepicker/monthpicker?year=%d\", props.Year-(12-i)) }\n\t\t\thx-target=\"closest div\"\n\t\t\u003e\n\t\t\t{ fmt.Sprintf(\"%d\", props.Year-(12-i)) }\n\t\t\u003c/button\u003e\n\t}\n\t\u003cbutton\n\t\tclass=\"btn btn-sm border col-span-3\"\n\t\thx-get={ fmt.Sprintf(\"/datepicker/monthpicker?year=%d\", utcNow.Year()) }\n\t\thx-target=\"closest div\"\n\t\u003e\n\t\t{ fmt.Sprintf(\"%d\", utcNow.Year()) }\n\t\u003c/button\u003e\n}\n\ntempl DatePickerMonthPicker(props DatePickerProps) {\n\t{{ months := props.Months() }}\n\tfor _, m := range months {\n\t\t\u003cbutton\n\t\t\tclass={\n\t\t\t\t\"btn btn-sm border\",\n\t\t\t\ttempl.KV(\"border-primary\", m.Month() == time.Month(props.Month)),\n\t\t\t}\n\t\t\thx-get={ fmt.Sprintf(\"/datepicker?year=%d\u0026month=%d\", props.Year, m.Month()) }\n\t\t\thx-target=\"div[name=datepicker-div]\"\n\t\t\thx-swap=\"outerHTML\"\n\t\t\u003e\n\t\t\t{ m.Format(\"Jan\") }\n\t\t\u003c/button\u003e\n\t}\n}\n```"
    },
    {
      "name": "file_input",
      "code": "```go\ntype FileInputProps struct {\n\tName            string\n\tLabel           string\n\tValue           string\n\tDescription     string\n\tAttrs           templ.Attributes\n\tDisabledMessage string\n\tRequired        bool\n\tSize            string\n}\n\ntempl FileInput(props FileInputProps) {\n\t\u003cfieldset\n\t\tclass=\"fieldset tooltip tooltip-top w-full\"\n\t\tif props.DisabledMessage != \"\" {\n\t\t\tdata-tip={ props.DisabledMessage }\n\t\t}\n\t\u003e\n\t\tif props.Label != \"\" {\n\t\t\t\u003clegend class=\"fieldset-legend\"\u003e{ props.Label }\u003c/legend\u003e\n\t\t}\n\t\t\u003cinput\n\t\t\ttype=\"file\"\n\t\t\tclass={\n\t\t\t\t\"file-input w-full\",\n\t\t\t\ttempl.KV(\"file-input-xs\", props.Size == \"xs\"),\n\t\t\t\ttempl.KV(\"file-input-sm\", props.Size == \"sm\"),\n\t\t\t\ttempl.KV(\"file-input-lg\", props.Size == \"lg\"),\n\t\t\t\ttempl.KV(\"file-input-xl\", props.Size == \"xl\"),\n\t\t\t}\n\t\t\tname={ props.Name }\n\t\t\tif props.DisabledMessage != \"\" {\n\t\t\t\tdisabled\n\t\t\t}\n\t\t\t{ props.Attrs... }\n\t\t/\u003e\n\t\tif props.Description != \"\" {\n\t\t\t\u003clabel class=\"fieldset-label\"\u003e{ props.Description }\u003c/label\u003e\n\t\t}\n\t\u003c/fieldset\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/file-input"
    },
    {
      "name": "input",
      "code": "```go\ntype InputProps struct {\n\t// common\n\tName            string\n\tLabel           string\n\tType            string // defaults to \"text\"\n\tValue           string\n\tPlaceholder     string\n\tDescription     string\n\tError           string\n\tDisabledMessage string\n\tSize            string // xs sm lg xl, default: md\n\tRequired        bool\n\tIcon            templ.Component\n\tAttrs           templ.Attributes\n\n\t// text input\n\tMinLength     string\n\tMaxLength     string\n\tPattern       string\n\tValidatorHint string\n\n\t// integer/decimal input\n\tMin string\n\tMax string\n\n\t// decimal input\n\tStep string\n}\n\ntempl Input(props InputProps) {\n\t\u003cfieldset class=\"fieldset\"\u003e\n\t\tif props.Label != \"\" {\n\t\t\t\u003clegend class=\"fieldset-legend\"\u003e{ props.Label }\u003c/legend\u003e\n\t\t}\n\t\t\u003clabel\n\t\t\tfor={ props.Name }\n\t\t\tclass={\n\t\t\t\t\"input validator tooltip tooltip-top\",\n\t\t\t\ttempl.KV(\"tooltip tooltip-top\", props.DisabledMessage != \"\"),\n\t\t\t\ttempl.KV(\"input-xs\", props.Size == \"xs\"),\n\t\t\t\ttempl.KV(\"input-sm\", props.Size == \"sm\"),\n\t\t\t\ttempl.KV(\"input-lg\", props.Size == \"lg\"),\n\t\t\t\ttempl.KV(\"input-xl\", props.Size == \"xl\"),\n\t\t\t}\n\t\t\tif props.DisabledMessage != \"\" {\n\t\t\t\tdata-tip={ props.DisabledMessage }\n\t\t\t}\n\t\t\u003e\n\t\t\tif props.Icon != nil {\n\t\t\t\t@props.Icon\n\t\t\t}\n\t\t\t\u003cinput\n\t\t\t\tname={ props.Name }\n\t\t\t\tif props.Type == \"\" {\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t} else {\n\t\t\t\t\ttype={ props.Type }\n\t\t\t\t}\n\t\t\t\tvalue={ props.Value }\n\t\t\t\tplaceholder={ props.Placeholder }\n\t\t\t\tif props.Required {\n\t\t\t\t\trequired\n\t\t\t\t}\n\t\t\t\tif props.Pattern != \"\" {\n\t\t\t\t\tpattern={ props.Pattern }\n\t\t\t\t}\n\t\t\t\tif props.ValidatorHint != \"\" {\n\t\t\t\t\ttitle={ props.ValidatorHint }\n\t\t\t\t}\n\t\t\t\tif props.DisabledMessage != \"\" {\n\t\t\t\t\tdisabled\n\t\t\t\t}\n\t\t\t\t{ props.Attrs... }\n\t\t\t/\u003e\n\t\t\u003c/label\u003e\n\t\tif props.Description != \"\" {\n\t\t\t\u003cdiv class=\"label\"\u003e{ props.Description }\u003c/div\u003e\n\t\t}\n\t\tif props.Error != \"\" {\n\t\t\t\u003cp class=\"text-xs text-error max-w-xs\"\u003e{ props.Error }\u003c/p\u003e\n\t\t}\n\t\tif props.ValidatorHint != \"\" {\n\t\t\t\u003cp class=\"validator-hint hidden text-xs max-w-xs !mt-0\"\u003e{ props.ValidatorHint }\u003c/p\u003e\n\t\t}\n\t\u003c/fieldset\u003e\n}\n```"
    },
    {
      "name": "radio",
      "code": "```go\ntype RadioProps struct {\n\tName   string\n\tValues map[string]string\n\tClass  string\n\tSize   string\n}\n\ntempl Radio(props RadioProps) {\n\t\u003cdiv class=\"space-y-2 w-full\"\u003e\n\t\tfor l, v := range props.Values {\n\t\t\t\u003clabel for={ props.Name } class=\"label cursor-pointer grid grid-cols-7\"\u003e\n\t\t\t\t\u003cspan\n\t\t\t\t\tclass={\n\t\t\t\t\t\t\"col-span-6 text-wrap\",\n\t\t\t\t\t\ttempl.KV(\"text-xs\", props.Size == \"xs\"),\n\t\t\t\t\t\ttempl.KV(\"text-sm\", props.Size == \"sm\"),\n\t\t\t\t\t\ttempl.KV(\"text-lg\", props.Size == \"lg\"),\n\t\t\t\t\t\ttempl.KV(\"text-xl\", props.Size == \"xl\"),\n\t\t\t\t\t}\n\t\t\t\t\u003e{ l }\u003c/span\u003e\n\t\t\t\t\u003cinput\n\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\tname={ props.Name }\n\t\t\t\t\tvalue={ v }\n\t\t\t\t\tclass={\n\t\t\t\t\t\t\"radio col-span-1\", props.Class,\n\t\t\t\t\t\ttempl.KV(\"radio-xs\", props.Size == \"xs\"),\n\t\t\t\t\t\ttempl.KV(\"radio-sm\", props.Size == \"sm\"),\n\t\t\t\t\t\ttempl.KV(\"radio-lg\", props.Size == \"lg\"),\n\t\t\t\t\t\ttempl.KV(\"radio-xl\", props.Size == \"xl\"),\n\t\t\t\t\t}\n\t\t\t\t/\u003e\n\t\t\t\u003c/label\u003e\n\t\t}\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/radio"
    },
    {
      "name": "range",
      "code": "```go\ntype RangeProps struct {\n\tID    string\n\tLabel string\n\tName  string\n\tValue int\n\tMin   int\n\tMax   int\n\tStep  int\n\tClass string\n\tSize  string\n}\n\n// Note: usage requires alpine.js\ntempl Range(props RangeProps) {\n\t\u003cscript src=\"/static/js/alpine.js\" defer\u003e\u003c/script\u003e\n\t\u003cdiv class=\"form-control\"\u003e\n\t\t\u003clabel\n\t\t\tclass=\"label space-x-1\"\n\t\t\tx-data={ fmt.Sprintf(\"{ value: %d }\", props.Value) }\n\t\t\u003e\n\t\t\tif props.Label != \"\" {\n\t\t\t\t\u003cspan\n\t\t\t\t\tclass={\n\t\t\t\t\t\ttempl.KV(\"text-xs\", props.Size == \"xs\"),\n\t\t\t\t\t\ttempl.KV(\"text-sm\", props.Size == \"sm\"),\n\t\t\t\t\t\ttempl.KV(\"text-lg\", props.Size == \"lg\"),\n\t\t\t\t\t\ttempl.KV(\"text-xl\", props.Size == \"xl\"),\n\t\t\t\t\t}\n\t\t\t\t\u003e{ props.Label }\u003c/span\u003e\n\t\t\t}\n\t\t\t\u003cinput\n\t\t\t\ttype=\"range\"\n\t\t\t\tif props.ID != \"\" {\n\t\t\t\t\tid={ props.ID }\n\t\t\t\t}\n\t\t\t\tname={ props.Name }\n\t\t\t\tmin={ fmt.Sprintf(\"%d\", props.Min) }\n\t\t\t\tmax={ fmt.Sprintf(\"%d\", props.Max) }\n\t\t\t\tx-model=\"value\"\n\t\t\t\tclass={\n\t\t\t\t\t\"range\", props.Class,\n\t\t\t\t\ttempl.KV(\"range-xs\", props.Size == \"xs\"),\n\t\t\t\t\ttempl.KV(\"range-sm\", props.Size == \"sm\"),\n\t\t\t\t\ttempl.KV(\"range-lg\", props.Size == \"lg\"),\n\t\t\t\t\ttempl.KV(\"range-xl\", props.Size == \"xl\"),\n\t\t\t\t}\n\t\t\t\tstep={ fmt.Sprintf(\"%d\", props.Step) }\n\t\t\t/\u003e\n\t\t\t\u003cdiv x-text=\"value\" class=\"w-full max-w-7\"\u003e\u003c/div\u003e\n\t\t\u003c/label\u003e\n\t\u003c/div\u003e\n}\n\n// Note: usage requires datastar.js\ntempl DatastarRange(props RangeProps) {\n\t\u003cscript type=\"module\" src=\"/static/js/datastar.js\"\u003e\u003c/script\u003e\n\t\u003cdiv class=\"form-control\"\u003e\n\t\t\u003clabel\n\t\t\tclass=\"label space-x-1\"\n\t\t\tdata-signals={ fmt.Sprintf(\"{value: %d}\", props.Value) }\n\t\t\u003e\n\t\t\tif props.Label != \"\" {\n\t\t\t\t\u003cspan\n\t\t\t\t\tclass={\n\t\t\t\t\t\ttempl.KV(\"text-xs\", props.Size == \"xs\"),\n\t\t\t\t\t\ttempl.KV(\"text-sm\", props.Size == \"sm\"),\n\t\t\t\t\t\ttempl.KV(\"text-lg\", props.Size == \"lg\"),\n\t\t\t\t\t\ttempl.KV(\"text-xl\", props.Size == \"xl\"),\n\t\t\t\t\t}\n\t\t\t\t\u003e{ props.Label }\u003c/span\u003e\n\t\t\t}\n\t\t\t\u003cinput\n\t\t\t\ttype=\"range\"\n\t\t\t\tif props.ID != \"\" {\n\t\t\t\t\tid={ props.ID }\n\t\t\t\t}\n\t\t\t\tname={ props.Name }\n\t\t\t\tmin={ fmt.Sprintf(\"%d\", props.Min) }\n\t\t\t\tmax={ fmt.Sprintf(\"%d\", props.Max) }\n\t\t\t\tclass={\n\t\t\t\t\t\"range\", props.Class,\n\t\t\t\t\ttempl.KV(\"range-xs\", props.Size == \"xs\"),\n\t\t\t\t\ttempl.KV(\"range-sm\", props.Size == \"sm\"),\n\t\t\t\t\ttempl.KV(\"range-lg\", props.Size == \"lg\"),\n\t\t\t\t\ttempl.KV(\"range-xl\", props.Size == \"xl\"),\n\t\t\t\t}\n\t\t\t\tstep={ fmt.Sprintf(\"%d\", props.Step) }\n\t\t\t\tdata-bind-value\n\t\t\t/\u003e\n\t\t\t\u003cdiv\n\t\t\t\tclass=\"w-full max-w-7\"\n\t\t\t\tdata-text=\"$value\"\n\t\t\t\u003e\u003c/div\u003e\n\t\t\u003c/label\u003e\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/range"
    },
    {
      "name": "rating",
      "code": "```go\ntype RatingProps struct {\n\tName  string\n\tMin   int\n\tMax   int\n\tClass string\n\tValue int\n}\n\ntempl Rating(props RatingProps) {\n\t\u003cdiv class=\"rating\"\u003e\n\t\tfor i := props.Min; i \u003c= props.Max; i++ {\n\t\t\tif i == 0 {\n\t\t\t\t\u003cinput\n\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\tname={ props.Name }\n\t\t\t\t\tvalue={ fmt.Sprintf(\"%d\", i) }\n\t\t\t\t\tclass=\"rating-hidden\"\n\t\t\t\t/\u003e\n\t\t\t} else {\n\t\t\t\t\u003cinput\n\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\tname={ props.Name }\n\t\t\t\t\tvalue={ fmt.Sprintf(\"%d\", i) }\n\t\t\t\t\tclass={ \"mask mask-star-2 bg-yellow-400\", props.Class }\n\t\t\t\t\tif i+1 == props.Max {\n\t\t\t\t\t\tchecked=\"checked\"\n\t\t\t\t\t}\n\t\t\t\t/\u003e\n\t\t\t}\n\t\t}\n\t\u003c/div\u003e\n}\n\ntempl RatingDisplay(props RatingProps) {\n\t\u003cdiv class=\"rating\"\u003e\n\t\tfor i := props.Min; i \u003c= props.Max; i++ {\n\t\t\tif i == 0 {\n\t\t\t\t\u003cinput\n\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\tname={ props.Name }\n\t\t\t\t\tvalue={ fmt.Sprintf(\"%d\", i) }\n\t\t\t\t\tclass=\"rating-hidden cursor-default\"\n\t\t\t\t\tdisabled\n\t\t\t\t/\u003e\n\t\t\t} else {\n\t\t\t\t\u003cinput\n\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\tname={ props.Name }\n\t\t\t\t\tvalue={ fmt.Sprintf(\"%d\", i) }\n\t\t\t\t\tclass={ \"mask mask-star-2 bg-accent cursor-default\", props.Class }\n\t\t\t\t\tif i == props.Value {\n\t\t\t\t\t\tchecked=\"checked\"\n\t\t\t\t\t}\n\t\t\t\t\tdisabled\n\t\t\t\t/\u003e\n\t\t\t}\n\t\t}\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/rating"
    },
    {
      "name": "select",
      "code": "```go\ntype SelectProps struct {\n\tID          string\n\tLabel       string\n\tName        string\n\tDescription string\n\tClass       string\n\tSize        string\n\tRequired    bool\n\tOptions     []SelectOption\n\tAttrs       templ.Attributes\n}\n\ntype SelectOption struct {\n\tLabel    string\n\tValue    string\n\tSelected bool\n\tDisabled bool\n}\n\ntempl Select(props SelectProps) {\n\t\u003cfieldset class=\"fieldset\"\u003e\n\t\tif props.Label != \"\" {\n\t\t\t\u003clegend class=\"fieldset-legend\"\u003e{ props.Label }\u003c/legend\u003e\n\t\t}\n\t\t\u003cselect\n\t\t\tclass={\n\t\t\t\t\"select w-full\",\n\t\t\t\tprops.Class,\n\t\t\t\ttempl.KV(\"select-xs\", props.Size == \"xs\"),\n\t\t\t\ttempl.KV(\"select-sm\", props.Size == \"sm\"),\n\t\t\t\ttempl.KV(\"select-lg\", props.Size == \"lg\"),\n\t\t\t\ttempl.KV(\"select-xl\", props.Size == \"xl\"),\n\t\t\t}\n\t\t\tif props.ID != \"\" {\n\t\t\t\tid={ props.ID }\n\t\t\t}\n\t\t\tname={ props.Name }\n\t\t\tif props.Required {\n\t\t\t\trequired\n\t\t\t}\n\t\t\t{ props.Attrs... }\n\t\t\u003e\n\t\t\t@SelectOptions(props.Options)\n\t\t\u003c/select\u003e\n\t\tif props.Description != \"\" {\n\t\t\t\u003cspan class=\"label\"\u003e{ props.Description }\u003c/span\u003e\n\t\t}\n\t\u003c/fieldset\u003e\n}\n\ntempl SelectOptions(options []SelectOption) {\n\tfor i := range options {\n\t\t\u003coption\n\t\t\tif options[i].Selected {\n\t\t\t\tselected\n\t\t\t}\n\t\t\tif options[i].Disabled {\n\t\t\t\tdisabled\n\t\t\t}\n\t\t\tvalue={ options[i].Value }\n\t\t\u003e\n\t\t\t{ options[i].Label }\n\t\t\u003c/option\u003e\n\t}\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/select"
    },
    {
      "name": "textarea",
      "code": "```go\ntype TextareaProps struct {\n\tID          string\n\tLabel       string\n\tName        string\n\tPlaceholder string\n\tValue       string\n\tDescription string\n\tErr         string\n\tClass       string\n\tSize        string\n\tRequired    bool\n\tRows        int\n\tAttrs       templ.Attributes\n}\n\ntempl Textarea(props TextareaProps) {\n\t\u003cfieldset class=\"fieldset\"\u003e\n\t\tif props.Label != \"\" {\n\t\t\t\u003clegend class=\"fieldset-legend\"\u003e{ props.Label }\u003c/legend\u003e\n\t\t}\n\t\t\u003ctextarea\n\t\t\t{ props.Attrs... }\n\t\t\tif props.ID != \"\" {\n\t\t\t\tid={ props.ID }\n\t\t\t}\n\t\t\tname={ props.Name }\n\t\t\tplaceholder={ props.Placeholder }\n\t\t\tclass={\n\t\t\t\t\"textarea\",\n\t\t\t\tprops.Class,\n\t\t\t\ttempl.KV(\"textarea-error\", props.Err != \"\"),\n\t\t\t\ttempl.KV(\"textarea-xs\", props.Size == \"xs\"),\n\t\t\t\ttempl.KV(\"textarea-sm\", props.Size == \"sm\"),\n\t\t\t\ttempl.KV(\"textarea-lg\", props.Size == \"lg\"),\n\t\t\t\ttempl.KV(\"textarea-xl\", props.Size == \"xl\"),\n\t\t\t}\n\t\t\tif props.Rows \u003e 0 {\n\t\t\t\trows={ fmt.Sprintf(\"%d\", props.Rows) }\n\t\t\t} else {\n\t\t\t\trows=\"3\"\n\t\t\t}\n\t\t\tif props.Required {\n\t\t\t\trequired\n\t\t\t}\n\t\t\u003e\n\t\t\t{ props.Value }\n\t\t\u003c/textarea\u003e\n\t\tif props.Description != \"\" {\n\t\t\t\u003cdiv class=\"label\"\u003e{ props.Description }\u003c/div\u003e\n\t\t}\n\t\t\u003cdiv class=\"h-6 !p-0 fieldset-label text-error text-sm\"\u003e{ props.Err }\u003c/div\u003e\n\t\u003c/fieldset\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/textarea"
    },
    {
      "name": "time_slot_picker",
      "code": "```go\ntype TimeSlotPickerProps struct {\n\tID          string\n\tCurrentDate time.Time\n\tTimeSlots   []TimeSlot\n\tPickerURL   string\n\tReserveURL  string\n}\n\ntype TimeSlot struct {\n\tStart time.Time\n\tEnd   time.Time\n}\n\nfunc (x *TimeSlotPickerProps) Days() []time.Time {\n\tdate := time.Date(x.CurrentDate.Year(), x.CurrentDate.Month(), x.CurrentDate.Day(), 0, 0, 0, 0, x.CurrentDate.Location())\n\tdates := make([]time.Time, 7)\n\tdates[0] = date\n\tfor i := range 6 {\n\t\tdate = date.Add(24 * time.Hour)\n\t\tdates[i+1] = date\n\t}\n\treturn dates\n}\n\nfunc (x *TimeSlotPickerProps) GetSlots(day time.Time) []TimeSlot {\n\tslots := make([]TimeSlot, 0)\n\tnow := time.Now().UTC()\n\tnow = time.Date(\n\t\tnow.Year(), now.Month(), now.Day(),\n\t\tnow.Hour(), 0, 0, 0,\n\t\tnow.Location()).Add(time.Duration(24-now.Hour()) * time.Hour)\n\tfor _, s := range x.TimeSlots {\n\t\tif s.Start.After(now) \u0026\u0026 s.Start.Format(\"20060102\") == day.Format(\"20060102\") {\n\t\t\tslots = append(slots, s)\n\t\t}\n\t}\n\treturn slots\n}\n\ntempl TimeSlotPicker(props TimeSlotPickerProps) {\n\t\u003cdiv id={ props.ID } class=\"p-4\"\u003e\n\t\t\u003cdiv class=\"grid grid-cols-7 gap-1 h-[500px] w-full max-w-screen-xl\"\u003e\n\t\t\tfor _, day := range props.Days() {\n\t\t\t\t@timeSlotPickerDay(props, day)\n\t\t\t}\n\t\t\u003c/div\u003e\n\t\t@timeSlotPickerControls(props)\n\t\u003c/div\u003e\n}\n\ntempl timeSlotPickerDay(props TimeSlotPickerProps, day time.Time) {\n\t\u003cdiv\n\t\tclass={\n\t\t\t\"flex flex-col space-y-2 border border-base-content rounded-box text-sm overflow-y-auto\",\n\t\t\ttempl.KV(\"border-primary\", time.Now().UTC().Format(\"20060102\") == day.Format(\"20060102\")),\n\t\t}\n\t\u003e\n\t\t\u003cdiv class=\"text-center pt-1\"\u003e\n\t\t\t\u003cspan\u003e{ day.Format(\"Mon Jan 02\") }\u003c/span\u003e\n\t\t\t\u003cdiv class=\"divider !my-0 !py-0\"\u003e\u003c/div\u003e\n\t\t\u003c/div\u003e\n\t\t\u003cul class=\"space-y-1\"\u003e\n\t\t\tfor _, slot := range props.GetSlots(day) {\n\t\t\t\t{{ slotName := \"time_slot_\" + slot.Start.Format(\"200601021504\") }}\n\t\t\t\t@Modal(ModalProps{\n\t\t\t\t\tID: slotName,\n\t\t\t\t\tLabel: timeSlotButton(\n\t\t\t\t\t\tslot,\n\t\t\t\t\t\ttempl.Attributes{\"onclick\": slotName + \".showModal()\"},\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t\t) {\n\t\t\t\t\t@timeSlotModalContent(slot, slotName, props.ReserveURL)\n\t\t\t\t}\n\t\t\t}\n\t\t\u003c/ul\u003e\n\t\u003c/div\u003e\n}\n\ntempl timeSlotButton(slot TimeSlot, attrs templ.Attributes) {\n\t\u003cbutton class=\"btn btn-sm btn-ghost w-full\" { attrs... }\u003e\n\t\t{ slot.Start.Format(\"15:04\") } - { slot.End.Format(\"15:04\") }\n\t\u003c/button\u003e\n}\n\ntempl timeSlotModalContent(slot TimeSlot, slotName, reserveURL string) {\n\t\u003cdiv\u003e\n\t\t\u003cdiv class=\"flex items-center space-x-2\"\u003e\n\t\t\t\u003cdiv class=\"flex justify-center items-center\"\u003e\n\t\t\t\t\u003csvg\n\t\t\t\t\tclass=\"h-8 w-8\"\n\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\u003e\n\t\t\t\t\t\u003cpath class=\"stroke-current\" d=\"M2 12C2 7.28595 2 4.92893 3.46447 3.46447C4.92893 2 7.28595 2 12 2C16.714 2 19.0711 2 20.5355 3.46447C22 4.92893 22 7.28595 22 12C22 16.714 22 19.0711 20.5355 20.5355C19.0711 22 16.714 22 12 22C7.28595 22 4.92893 22 3.46447 20.5355C2 19.0711 2 16.714 2 12Z\" stroke-width=\"1.5\"\u003e\u003c/path\u003e\n\t\t\t\t\t\u003cpath class=\"stroke-current\" d=\"M10.125 8.875C10.125 7.83947 10.9645 7 12 7C13.0355 7 13.875 7.83947 13.875 8.875C13.875 9.56245 13.505 10.1635 12.9534 10.4899C12.478 10.7711 12 11.1977 12 11.75V13\" stroke-width=\"1.5\" stroke-linecap=\"round\"\u003e\u003c/path\u003e\n\t\t\t\t\t\u003ccircle class=\"fill-current\" cx=\"12\" cy=\"16\" r=\"1\"\u003e\u003c/circle\u003e\n\t\t\t\t\u003c/svg\u003e\n\t\t\t\u003c/div\u003e\n\t\t\t\u003cp class=\"col-span-7\"\u003e\n\t\t\t\tReserve a time slot \u003cb\u003e{ slot.Start.Format(\"15:04\") }\u003c/b\u003e - \u003cb\u003e{ slot.End.Format(\"15:04\") }\u003c/b\u003e, \u003cb\u003e{ slot.Start.Format(\"Monday January 02\") }\u003c/b\u003e?\n\t\t\t\u003c/p\u003e\n\t\t\u003c/div\u003e\n\t\t\u003cdiv class=\"flex justify-between items-center mt-8\"\u003e\n\t\t\t\u003cbutton\n\t\t\t\tid=\"modal-confirm-reservation\"\n\t\t\t\tclass=\"btn btn-sm btn-primary\"\n\t\t\t\thx-post={ reserveURL + \"?start=\" + slot.Start.Format(\"2006-01-02-15-04\") + \"\u0026end=\" + slot.End.Format(\"2006-01-02-15-04\") }\n\t\t\t\u003e\n\t\t\t\tReserve\n\t\t\t\u003c/button\u003e\n\t\t\t\u003cbutton class=\"btn btn-sm\" { templ.Attributes{\"onclick\": slotName + \".close()\"}... }\u003e\n\t\t\t\tCancel\n\t\t\t\u003c/button\u003e\n\t\t\u003c/div\u003e\n\t\t\u003cscript\u003e\n            ((modal) =\u003e {\n                document.addEventListener(\"htmx:afterRequest\", (evt) =\u003e {\n                    if (evt.detail.elt.id === \"modal-confirm-reservation\" \u0026\u0026 evt.detail.successful) {\n                        modal.close()\n                    }\n                })\n            })(document.currentScript.closest(\"dialog.modal\"))\n        \u003c/script\u003e\n\t\u003c/div\u003e\n}\n\ntempl timeSlotPickerControls(props TimeSlotPickerProps) {\n\t\u003cdiv class=\"flex justify-between items-center py-2\"\u003e\n\t\t\u003cbutton\n\t\t\thx-get={ props.PickerURL + \"?date=\" + props.CurrentDate.Add(time.Duration(-7*24)*time.Hour).Format(\"2006-01-02\") }\n\t\t\thx-target={ \"#\" + props.ID }\n\t\t\thx-swap=\"outerHTML\"\n\t\t\tclass={ \"btn btn-ghost btn-sm disabled:opacity-50\", }\n\t\t\tif props.CurrentDate.Format(\"2006-01-02\") == time.Now().UTC().Format(\"2006-01-02\") {\n\t\t\t\tdisabled\n\t\t\t}\n\t\t\u003e\n\t\t\t@chevronLeft()\n\t\t\u003c/button\u003e\n\t\t\u003cbutton\n\t\t\thx-get={ props.PickerURL + \"?date=\" + props.CurrentDate.Add(time.Duration(7*24)*time.Hour).Format(\"2006-01-02\") }\n\t\t\thx-target={ \"#\" + props.ID }\n\t\t\thx-swap=\"outerHTML\"\n\t\t\tclass=\"btn btn-ghost btn-sm\"\n\t\t\u003e\n\t\t\t@chevronRight()\n\t\t\u003c/button\u003e\n\t\u003c/div\u003e\n}\n\ntempl chevronLeft() {\n\t\u003csvg\n\t\tclass=\"h-6 w-6\"\n\t\tviewBox=\"0 0 24 24\"\n\t\tfill=\"none\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\u003e\n\t\t\u003cpath class=\"stroke-base-content\" d=\"M15 6L9 12L15 18\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n\ntempl chevronRight() {\n\t\u003csvg\n\t\tclass=\"h-6 w-6\"\n\t\tviewBox=\"0 0 24 24\"\n\t\tfill=\"none\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\u003e\n\t\t\u003cpath class=\"stroke-base-content\" d=\"M9 6L15 12L9 18\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n```"
    },
    {
      "name": "toggle",
      "code": "```go\ntype ToggleProps struct {\n\tID        string\n\tBefore    string\n\tAfter     string\n\tName      string\n\tChecked   bool\n\tClass     string\n\tHighlight bool\n\tAttrs     templ.Attributes\n\tSize      string\n}\n\ntempl Toggle(props ToggleProps) {\n\t\u003cdiv class=\"flex justify-center\"\u003e\n\t\t\u003clabel class=\"label cursor-pointer space-x-2 mx-auto\"\u003e\n\t\t\tif props.Before != \"\" {\n\t\t\t\t\u003cspan\n\t\t\t\t\tclass={\n\t\t\t\t\t\ttempl.KV(\"text-primary\", props.Highlight \u0026\u0026 !props.Checked),\n\t\t\t\t\t\ttempl.KV(\"text-xs\", props.Size == \"xs\"),\n\t\t\t\t\t\ttempl.KV(\"text-sm\", props.Size == \"sm\"),\n\t\t\t\t\t\ttempl.KV(\"text-lg\", props.Size == \"lg\"),\n\t\t\t\t\t\ttempl.KV(\"text-xl\", props.Size == \"xl\"),\n\t\t\t\t\t}\n\t\t\t\t\u003e\n\t\t\t\t\t{ props.Before }\n\t\t\t\t\u003c/span\u003e\n\t\t\t}\n\t\t\t\u003cinput\n\t\t\t\t{ props.Attrs... }\n\t\t\t\ttype=\"checkbox\"\n\t\t\t\tif props.ID != \"\" {\n\t\t\t\t\tid={ props.ID }\n\t\t\t\t}\n\t\t\t\tname={ props.Name }\n\t\t\t\tclass={\n\t\t\t\t\t\"toggle\", props.Class,\n\t\t\t\t\ttempl.KV(\"toggle-xs\", props.Size == \"xs\"),\n\t\t\t\t\ttempl.KV(\"toggle-sm\", props.Size == \"sm\"),\n\t\t\t\t\ttempl.KV(\"toggle-lg\", props.Size == \"lg\"),\n\t\t\t\t\ttempl.KV(\"toggle-xl\", props.Size == \"xl\"),\n\t\t\t\t}\n\t\t\t\tif props.Checked {\n\t\t\t\t\tchecked=\"checked\"\n\t\t\t\t}\n\t\t\t\tif props.Highlight {\n\t\t\t\t\tonclick=\"toggler(event)\"\n\t\t\t\t}\n\t\t\t/\u003e\n\t\t\tif props.After != \"\" {\n\t\t\t\t\u003cspan\n\t\t\t\t\tclass={\n\t\t\t\t\t\t\"label-text\",\n\t\t\t\t\t\ttempl.KV(\"text-primary\", props.Highlight \u0026\u0026 props.Checked),\n\t\t\t\t\t}\n\t\t\t\t\u003e\n\t\t\t\t\t{ props.After }\n\t\t\t\t\u003c/span\u003e\n\t\t\t}\n\t\t\u003c/label\u003e\n\t\tif props.Highlight {\n\t\t\t\u003cscript\u003e\n                function toggler(evt) {\n                    evt.target.previousElementSibling.classList.toggle(\"text-primary\")\n                    evt.target.nextElementSibling.classList.toggle(\"text-primary\")\n                }\n            \u003c/script\u003e\n\t\t}\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/toggle"
    }
  ],
  "feedback": [
    {
      "name": "alert",
      "code": "```go\ntempl Alert(class string) {\n\t\u003cdiv role=\"alert\" class={ \"alert\", class }\u003e\n\t\t{ children... }\n\t\u003c/div\u003e\n}\n\ntempl AlertInfo(message string) {\n\t@Alert(\"alert-info\") {\n\t\t\u003csvg\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tfill=\"none\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tclass=\"stroke-info-content h-6 w-6 shrink-0\"\n\t\t\u003e\n\t\t\t\u003cpath\n\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\tstroke-width=\"2\"\n\t\t\t\td=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n\t\t\t\u003e\u003c/path\u003e\n\t\t\u003c/svg\u003e\n\t\t\u003cspan\u003e{ message }\u003c/span\u003e\n\t\t{ children... }\n\t}\n}\n\ntempl AlertSuccess(message string) {\n\t@Alert(\"alert-success\") {\n\t\t\u003csvg\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tfill=\"none\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tclass=\"stroke-success-content h-6 w-6 shrink-0\"\n\t\t\u003e\n\t\t\t\u003cpath\n\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\tstroke-width=\"2\"\n\t\t\t\td=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\"\n\t\t\t\u003e\u003c/path\u003e\n\t\t\u003c/svg\u003e\n\t\t\u003cspan\u003e{ message }\u003c/span\u003e\n\t\t{ children... }\n\t}\n}\n\ntempl AlertWarning(message string) {\n\t@Alert(\"alert-warning\") {\n\t\t\u003csvg\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tfill=\"none\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tclass=\"stroke-warning-content h-6 w-6 shrink-0\"\n\t\t\u003e\n\t\t\t\u003cpath\n\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\tstroke-width=\"2\"\n\t\t\t\td=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n\t\t\t\u003e\u003c/path\u003e\n\t\t\u003c/svg\u003e\n\t\t\u003cspan\u003e{ message }\u003c/span\u003e\n\t\t{ children... }\n\t}\n}\n\ntempl AlertError(message string) {\n\t@Alert(\"alert-error\") {\n\t\t\u003csvg\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tfill=\"none\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tclass=\"stroke-error-content h-6 w-6 shrink-0\"\n\t\t\u003e\n\t\t\t\u003cpath\n\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\tstroke-width=\"2\"\n\t\t\t\td=\"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z\"\n\t\t\t\u003e\u003c/path\u003e\n\t\t\u003c/svg\u003e\n\t\t\u003cspan\u003e{ message }\u003c/span\u003e\n\t\t{ children... }\n\t}\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/alert"
    },
    {
      "name": "skeleton",
      "code": "```go\ntempl Skeleton() {\n\t\u003cdiv class=\"flex flex-col gap-4\"\u003e\n\t\t\u003cdiv class=\"skeleton h-32 w-full\"\u003e\u003c/div\u003e\n\t\t\u003cdiv class=\"skeleton h-4 w-28\"\u003e\u003c/div\u003e\n\t\t\u003cdiv class=\"skeleton h-4 w-full\"\u003e\u003c/div\u003e\n\t\t\u003cdiv class=\"skeleton h-4 w-full\"\u003e\u003c/div\u003e\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/skeleton"
    },
    {
      "name": "status",
      "code": "```go\ntype StatusProps struct {\n\tCode              int\n\tTitle             string\n\tDescription       string\n\tReturnButtonLabel string\n\tReturnButtonAttrs templ.Attributes\n}\n\ntempl Status(props StatusProps) {\n\t\u003csection class=\"grid min-h-dvh place-content-center px-4\"\u003e\n\t\t\u003cdiv class=\"text-center\"\u003e\n\t\t\t\u003ch1 class=\"text-9xl font-black text-base-content/70\"\u003e\n\t\t\t\t{ fmt.Sprintf(\"%d\", props.Code) }\n\t\t\t\u003c/h1\u003e\n\t\t\t\u003cp class=\"text-2xl font-bold tracking-tight text-base-content sm:text-4xl\"\u003e\n\t\t\t\t{ props.Title }\n\t\t\t\u003c/p\u003e\n\t\t\t\u003cp class=\"mt-4 text-base-content/70\"\u003e\n\t\t\t\t{ props.Description }\n\t\t\t\u003c/p\u003e\n\t\t\t\u003ca\n\t\t\t\t{ props.ReturnButtonAttrs... }\n\t\t\t\tclass=\"mt-4 btn btn-primary\"\n\t\t\t\u003e\n\t\t\t\t{ props.ReturnButtonLabel }\n\t\t\t\u003c/a\u003e\n\t\t\u003c/div\u003e\n\t\u003c/section\u003e\n}\n```"
    },
    {
      "name": "toast",
      "code": "```go\ntype ToastProps struct {\n\tName       string\n\tToastClass string\n\tAlertClass string\n}\n\ntempl Toast(props ToastProps) {\n\t\u003cdiv name={ props.Name } class={ \"toast\", props.ToastClass }\u003e\n\t\t\u003cdiv class={ \"alert\", props.AlertClass }\u003e\n\t\t\t{ children... }\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/toast"
    },
    {
      "name": "tooltip",
      "code": "```go\ntype TooltipProps struct {\n\tTip   string\n\tClass string\n}\n\ntempl Tooltip(props TooltipProps) {\n\t\u003cdiv class={ \"tooltip\", props.Class } data-tip={ props.Tip }\u003e\n\t\t{ children... }\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/tooltip"
    }
  ],
  "layout": [
    {
      "name": "banner",
      "code": "```go\ntype BannerProps struct {\n\tTitle       templ.Component\n\tDescription string\n}\n\ntempl Banner(props BannerProps) {\n\t\u003csection\u003e\n\t\t\u003cdiv class=\"mx-auto max-w-screen-xl px-4 py-32 lg:flex lg:items-center\"\u003e\n\t\t\t\u003cdiv class=\"mx-auto max-w-xl text-center\"\u003e\n\t\t\t\t@props.Title\n\t\t\t\t\u003cp class=\"mt-4 sm:text-xl/relaxed\"\u003e\n\t\t\t\t\t{ props.Description }\n\t\t\t\t\u003c/p\u003e\n\t\t\t\t\u003cdiv class=\"mt-8 flex flex-wrap justify-center gap-4\"\u003e\n\t\t\t\t\t// call to action\n\t\t\t\t\t{ children... }\n\t\t\t\t\u003c/div\u003e\n\t\t\t\u003c/div\u003e\n\t\t\u003c/div\u003e\n\t\u003c/section\u003e\n}\n```"
    },
    {
      "name": "drawer",
      "code": "```go\ntempl Drawer(toggle templ.Component, sidebar templ.Component) {\n\t\u003cdiv class=\"drawer\"\u003e\n\t\t\u003cinput id=\"my-drawer\" type=\"checkbox\" class=\"drawer-toggle\"/\u003e\n\t\t\u003cdiv class=\"drawer-content\"\u003e\n\t\t\t\u003clabel for=\"my-drawer\" class=\"btn btn-primary drawer-button\"\u003e\n\t\t\t\t@toggle\n\t\t\t\u003c/label\u003e\n\t\t\t{ children... }\n\t\t\u003c/div\u003e\n\t\t\u003cdiv class=\"drawer-side\"\u003e\n\t\t\t\u003clabel for=\"my-drawer\" aria-label=\"close sidebar\" class=\"drawer-overlay\"\u003e\u003c/label\u003e\n\t\t\t\u003cul class=\"menu bg-base-200 text-base-content min-h-full w-80 p-4\"\u003e\n\t\t\t\t@sidebar\n\t\t\t\u003c/ul\u003e\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/drawer"
    },
    {
      "name": "footer",
      "code": "```go\ntype FooterProps struct {\n\tIcon        templ.Component\n\tName        string\n\tDescription string\n\tCopyright   string\n\tAnchors     []AnchorProps\n}\n\ntempl Footer(props FooterProps) {\n\t\u003cfooter class=\"footer bg-base-200 text-base-content p-10 mt-24\"\u003e\n\t\t{ children... }\n\t\u003c/footer\u003e\n\t\u003cfooter class=\"footer bg-base-200 text-base-content border-base-300 border-t px-10 py-4\"\u003e\n\t\t\u003caside class=\"grid-flow-col items-center\"\u003e\n\t\t\tif props.Icon != nil {\n\t\t\t\t\u003cdiv class=\"w-6 h-6\"\u003e\n\t\t\t\t\t@props.Icon\n\t\t\t\t\u003c/div\u003e\n\t\t\t}\n\t\t\t\u003cp\u003e\n\t\t\t\tif props.Copyright != \"\" {\n\t\t\t\t\t\u003cspan\u003e\u0026copy; { props.Copyright }\u003c/span\u003e\n\t\t\t\t}\n\t\t\t\t{ props.Name }\n\t\t\t\t\u003cbr/\u003e\n\t\t\t\t{ props.Description }\n\t\t\t\u003c/p\u003e\n\t\t\u003c/aside\u003e\n\t\t\u003cnav class=\"md:place-self-center md:justify-self-end\"\u003e\n\t\t\t\u003cdiv class=\"grid grid-flow-col gap-4\"\u003e\n\t\t\t\tfor _, anchor := range props.Anchors {\n\t\t\t\t\t@Anchor(anchor)\n\t\t\t\t}\n\t\t\t\u003c/div\u003e\n\t\t\u003c/nav\u003e\n\t\u003c/footer\u003e\n}\n\ntempl FooterNav(title string, links []AnchorProps) {\n\t\u003cnav\u003e\n\t\t\u003ch6 class=\"footer-title\"\u003e{ title }\u003c/h6\u003e\n\t\tfor _, link := range links {\n\t\t\t\u003ca { link.Attrs... } class=\"link link-hover\"\u003e{ link.Label }\u003c/a\u003e\n\t\t}\n\t\u003c/nav\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/footer"
    },
    {
      "name": "hero",
      "code": "```go\ntype HeroProps struct {\n\tSource  string\n\tAlt     string\n\tReverse bool\n\tClass   string\n}\n\ntempl Hero(props HeroProps) {\n\t\u003cdiv class={ \"hero\", props.Class }\u003e\n\t\t\u003cdiv\n\t\t\tclass={\n\t\t\t\t\"hero-content\",\n\t\t\t\t\"flex-col\",\n\t\t\t\ttempl.KV(\"xl:flex-row\", !props.Reverse),\n\t\t\t\ttempl.KV(\"xl:flex-row-reverse\", props.Reverse),\n\t\t\t}\n\t\t\u003e\n\t\t\tif props.Source != \"\" {\n\t\t\t\t\u003cimg\n\t\t\t\t\tsrc={ props.Source }\n\t\t\t\t\talt={ props.Alt }\n\t\t\t\t\tclass=\"max-w-sm rounded-box shadow-2xl\"\n\t\t\t\t/\u003e\n\t\t\t}\n\t\t\t\u003cdiv\u003e\n\t\t\t\t{ children... }\n\t\t\t\u003c/div\u003e\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/hero"
    }
  ],
  "navigation": [
    {
      "name": "anchor",
      "code": "```go\ntype AnchorProps struct {\n\tHref      string\n\tLabel     string\n\tLeftIcon  templ.Component\n\tRightIcon templ.Component\n\tAttrs     templ.Attributes\n\tClass     string\n}\n\ntempl Anchor(props AnchorProps) {\n\t\u003ca\n\t\tif props.Href != \"\" {\n\t\t\thref={ templ.SafeURL(props.Href) }\n\t\t}\n\t\tclass={ \"group items-center cursor-pointer\", props.Class }\n\t\t{ props.Attrs... }\n\t\u003e\n\t\tif props.LeftIcon != nil {\n\t\t\t@props.LeftIcon\n\t\t}\n\t\t{ props.Label }\n\t\tif props.RightIcon != nil {\n\t\t\t@props.RightIcon\n\t\t}\n\t\u003c/a\u003e\n}\n```"
    },
    {
      "name": "breadcrumbs",
      "code": "```go\ntype BreadcrumbsProps []BreadcrumbsProp\n\ntype BreadcrumbsProp struct {\n\tLabel string\n\tAttrs templ.Attributes\n}\n\ntempl Breadcrumbs(props BreadcrumbsProps) {\n\t\u003cdiv class=\"breadcrumbs text-sm\"\u003e\n\t\t\u003cul\u003e\n\t\t\tfor i, prop := range props {\n\t\t\t\t\u003cli class=\"select-none\"\u003e\n\t\t\t\t\tif i \u003c len(props) - 1 {\n\t\t\t\t\t\t\u003ca { prop.Attrs... }\u003e{ prop.Label }\u003c/a\u003e\n\t\t\t\t\t} else {\n\t\t\t\t\t\t{ prop.Label }\n\t\t\t\t\t}\n\t\t\t\t\u003c/li\u003e\n\t\t\t}\n\t\t\u003c/ul\u003e\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/breadcrumbs"
    },
    {
      "name": "menu",
      "code": "```go\ntype MenuProps struct {\n\tTitle string\n\tClass string\n}\n\ntempl Menu(props MenuProps) {\n\t\u003cul class={ \"menu\", props.Class }\u003e\n\t\tif props.Title != \"\" {\n\t\t\t\u003ch2 class=\"font-bold\"\u003e{ props.Title }\u003c/h2\u003e\n\t\t}\n\t\t{ children... }\n\t\u003c/ul\u003e\n}\n\ntype MenuItemProps struct {\n\tLabel     string\n\tAttrs     templ.Attributes\n\tIcon      templ.Component\n\tIconAfter bool\n}\n\ntempl MenuItem(props MenuItemProps) {\n\t\u003cli\u003e\n\t\t\u003ca { props.Attrs... }\u003e\n\t\t\tif props.Icon != nil \u0026\u0026 !props.IconAfter {\n\t\t\t\t@props.Icon\n\t\t\t}\n\t\t\t{ props.Label }\n\t\t\tif props.Icon != nil \u0026\u0026 props.IconAfter {\n\t\t\t\t@props.Icon\n\t\t\t}\n\t\t\u003c/a\u003e\n\t\t\u003cul\u003e\n\t\t\t{ children... }\n\t\t\u003c/ul\u003e\n\t\u003c/li\u003e\n}\n\ntype SubmenuProps struct {\n\tTitle     string\n\tAttrs     templ.Attributes\n\tIcon      templ.Component\n\tIconAfter bool\n}\n\ntempl Submenu(props SubmenuProps) {\n\t\u003cli\u003e\n\t\t\u003cdetails { props.Attrs... }\u003e\n\t\t\t\u003csummary\u003e\n\t\t\t\tif props.Icon != nil \u0026\u0026 !props.IconAfter {\n\t\t\t\t\t@props.Icon\n\t\t\t\t}\n\t\t\t\t{ props.Title }\n\t\t\t\tif props.Icon != nil \u0026\u0026 props.IconAfter {\n\t\t\t\t\t@props.Icon\n\t\t\t\t}\n\t\t\t\u003c/summary\u003e\n\t\t\t\u003cul\u003e\n\t\t\t\t{ children... }\n\t\t\t\u003c/ul\u003e\n\t\t\u003c/details\u003e\n\t\u003c/li\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/menu"
    },
    {
      "name": "pagination",
      "code": "```go\ntype PaginationProps struct {\n\tURL      string\n\tPage     int\n\tLow      int\n\tHigh     int\n\tMaxPages int\n}\n\ntempl Pagination(id string, props PaginationProps) {\n\t\u003cdiv id={ id }\u003e\n\t\t\u003c!-- paginated content goes here --\u003e\n\t\t{ children... }\n\t\t\u003c!-- --\u003e\n\t\t\u003cdiv class=\"join\"\u003e\n\t\t\t@PaginationButton(id, props.URL, 1, props.Page == 1) {\n\t\t\t\t@AnglesLeft()\n\t\t\t}\n\t\t\t@PaginationButton(id, props.URL, props.Page-1, props.Page == 1) {\n\t\t\t\t@ChevronLeft()\n\t\t\t}\n\t\t\tfor i := props.Low; i \u003c= props.High; i++ {\n\t\t\t\t@PaginationButton(id, props.URL, i+1, props.Page == i+1) {\n\t\t\t\t\t{ fmt.Sprintf(\"%d\", i+1) }\n\t\t\t\t}\n\t\t\t}\n\t\t\t@PaginationButton(id, props.URL, props.Page+1, props.Page == props.MaxPages) {\n\t\t\t\t@ChevronRight()\n\t\t\t}\n\t\t\t@PaginationButton(id, props.URL, props.MaxPages, props.Page == props.MaxPages) {\n\t\t\t\t@AnglesRight()\n\t\t\t}\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n\ntempl PaginationButton(id, url string, urlPage int, disabled bool) {\n\t\u003cbutton\n\t\tif url != \"\" {\n\t\t\thx-get={ fmt.Sprintf(\"%s?page=%d\", url, urlPage) }\n\t\t\thx-target={ fmt.Sprintf(\"#%s\", id) }\n\t\t\thx-swap=\"outerHTML\"\n\t\t}\n\t\tclass={\n\t\t\t\"join-item btn btn-square disabled:opacity-40\",\n\t\t\ttempl.KV(\"btn-disabled\", disabled),\n\t\t}\n\t\tif disabled {\n\t\t\tdisabled\n\t\t}\n\t\u003e\n\t\t{ children... }\n\t\u003c/button\u003e\n}\n\ntempl AnglesRight() {\n\t\u003csvg\n\t\tclass=\"w-4 h-4\"\n\t\tviewBox=\"0 0 24 24\"\n\t\tfill=\"none\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\u003e\n\t\t\u003cpath\n\t\t\td=\"M6 17L11 12L6 7M13 17L18 12L13 7\"\n\t\t\tclass=\"stroke-base-content\"\n\t\t\tstroke-width=\"2\"\n\t\t\tstroke-linecap=\"round\"\n\t\t\tstroke-linejoin=\"round\"\n\t\t\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n\ntempl AnglesLeft() {\n\t\u003csvg\n\t\tclass=\"w-4 h-4\"\n\t\tviewBox=\"0 0 24 24\"\n\t\tfill=\"none\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\u003e\n\t\t\u003cpath\n\t\t\td=\"M18 17L13 12L18 7M11 17L6 12L11 7\"\n\t\t\tclass=\"stroke-base-content\"\n\t\t\tstroke-width=\"2\"\n\t\t\tstroke-linecap=\"round\"\n\t\t\tstroke-linejoin=\"round\"\n\t\t\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n\ntempl ChevronRight() {\n\t\u003csvg\n\t\tclass=\"w-4 h-4\"\n\t\tviewBox=\"0 0 24 24\"\n\t\tfill=\"none\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\u003e\n\t\t\u003cpath\n\t\t\td=\"M9 6L15 12L9 18\"\n\t\t\tclass=\"stroke-base-content\"\n\t\t\tstroke-width=\"2\"\n\t\t\tstroke-linecap=\"round\"\n\t\t\tstroke-linejoin=\"round\"\n\t\t\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n\ntempl ChevronLeft() {\n\t\u003csvg\n\t\tclass=\"w-4 h-4\"\n\t\tviewBox=\"0 0 24 24\"\n\t\tfill=\"none\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\u003e\n\t\t\u003cpath\n\t\t\td=\"M15 6L9 12L15 18\"\n\t\t\tclass=\"stroke-base-content\"\n\t\t\tstroke-width=\"2\"\n\t\t\tstroke-linecap=\"round\"\n\t\t\tstroke-linejoin=\"round\"\n\t\t\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/pagination"
    },
    {
      "name": "steps",
      "code": "```go\ntype StepProps struct {\n\tLabel string\n\tDone  bool\n\tAttrs templ.Attributes\n}\n\ntempl Steps() {\n\t\u003cul class=\"steps\"\u003e\n\t\t{ children... }\n\t\u003c/ul\u003e\n}\n\ntempl Step(props StepProps) {\n\t\u003cli\n\t\tclass={ \"step\", templ.KV(\"step-primary\", props.Done) }\n\t\u003e\n\t\t\u003ca { props.Attrs... }\u003e{ props.Label }\u003c/a\u003e\n\t\u003c/li\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/steps"
    },
    {
      "name": "tabs",
      "code": "```go\ntype TabsProps struct {\n\tName         string\n\tClass        string\n\tTabs         []TabProps\n\tContentClass string\n}\n\ntype TabProps struct {\n\tLabel   string\n\tContent templ.Component\n}\n\ntempl Tabs(props TabsProps) {\n\t\u003cdiv role=\"tablist\" class={ \"tabs\", props.Class }\u003e\n\t\tfor i, tab := range props.Tabs {\n\t\t\t\u003cinput\n\t\t\t\ttype=\"radio\"\n\t\t\t\tname={ props.Name }\n\t\t\t\trole=\"tab\"\n\t\t\t\tclass=\"tab\"\n\t\t\t\taria-label={ tab.Label }\n\t\t\t\tif i == 0 {\n\t\t\t\t\tchecked=\"checked\"\n\t\t\t\t}\n\t\t\t/\u003e\n\t\t\t\u003cdiv class={ \"tab-content\", props.ContentClass }\u003e\n\t\t\t\t@tab.Content\n\t\t\t\u003c/div\u003e\n\t\t}\n\t\u003c/div\u003e\n}\n```",
      "daisy_ui_url": "https://daisyui.com/components/tab"
    }
  ]
}

================================================
FILE: internal/assets/generated/component_example_code_map.json
================================================
{
  "accordion": [
    {
      "name": "AccordionWithCheckbox",
      "code": "```go\n\ntempl AccordionWithCheckbox() {\n\t\u003cdiv class=\"w-full flex join join-vertical pt-4\"\u003e\n\t\t@components.AccordionRow(components.AccordionRowProps{Label: \"Label 1\", Name: \"accordion-example-1\"}) {\n\t\t\t\u003cp class=\"pt-4\"\u003eLabel 1 content\u003c/p\u003e\n\t\t}\n\t\t@components.AccordionRow(components.AccordionRowProps{Label: \"Label 2\", Name: \"accordion-example-2\"}) {\n\t\t\t\u003ch2 class=\"text-xl font-bold py-4\"\u003eContent 2\u003c/h2\u003e\n\t\t\t\u003cp\u003eLabel 2 content\u003c/p\u003e\n\t\t}\n\t\t@components.AccordionRow(components.AccordionRowProps{Label: \"Label 3\", Name: \"accordion-example-3\"}) {\n\t\t\t\u003ch2 class=\"text-xl font-bold py-4\"\u003eContent 3\u003c/h2\u003e\n\t\t\t\u003cul class=\"list-disc [\u0026\u003eli]:ml-4\"\u003e\n\t\t\t\t\u003cli\u003eItem 1\u003c/li\u003e\n\t\t\t\t\u003cli\u003eItem 2\u003c/li\u003e\n\t\t\t\t\u003cli\u003eItem 3\u003c/li\u003e\n\t\t\t\u003c/ul\u003e\n\t\t}\n\t\u003c/div\u003e\n}\n\n```",
      "description": "Accordion with input type 'checkbox': multiple rows can be open at a time."
    },
    {
      "name": "AccordionWithRadio",
      "code": "```go\n\ntempl AccordionWithRadio() {\n\t\u003cdiv class=\"w-full flex join join-vertical pt-4\"\u003e\n\t\t@components.AccordionRow(components.AccordionRowProps{Label: \"Label 1\", Name: \"accordion-example-2\", Type: \"radio\"}) {\n\t\t\t\u003cp class=\"pt-4\"\u003eLabel 1 content\u003c/p\u003e\n\t\t}\n\t\t@components.AccordionRow(components.AccordionRowProps{Label: \"Label 2\", Name: \"accordion-example-2\", Type: \"radio\"}) {\n\t\t\t\u003ch2 class=\"text-xl font-bold py-4\"\u003eContent 2\u003c/h2\u003e\n\t\t\t\u003cp\u003eLabel 2 content\u003c/p\u003e\n\t\t}\n\t\t@components.AccordionRow(components.AccordionRowProps{Label: \"Label 3\", Name: \"accordion-example-2\", Type: \"radio\"}) {\n\t\t\t\u003ch2 class=\"text-xl font-bold py-4\"\u003eContent 3\u003c/h2\u003e\n\t\t\t\u003cul class=\"list-disc [\u0026\u003eli]:ml-4\"\u003e\n\t\t\t\t\u003cli\u003eItem 1\u003c/li\u003e\n\t\t\t\t\u003cli\u003eItem 2\u003c/li\u003e\n\t\t\t\t\u003cli\u003eItem 3\u003c/li\u003e\n\t\t\t\u003c/ul\u003e\n\t\t}\n\t\u003c/div\u003e\n}\n```",
      "description": "Accordion with input type 'radio': only a single row can be open at a time."
    }
  ],
  "active_search": [
    {
      "name": "ActiveSearchExampleTable",
      "code": "```go\ntempl ActiveSearchExampleTable() {\n\t\u003cdiv class=\"h-[600px]\"\u003e\n\t\t@ActiveSearchExample(\n\t\t\t\"active-search-example-table\",\n\t\t\t[]templ.Component{\n\t\t\t\tcomponents.PlainText(\"First name\"),\n\t\t\t\tcomponents.PlainText(\"Last name\"),\n\t\t\t\tcomponents.PlainText(\"Email\"),\n\t\t\t},\n\t\t\tactiveSearchTableDataComponents(),\n\t\t)\n\t\u003c/div\u003e\n}\n\ntempl ActiveSearchExample(id string, headers []templ.Component, rows []templ.Component) {\n\t\u003cdiv class=\"py-8\"\u003e\n\t\t@components.ActiveSearchInput(\n\t\t\tcomponents.ActiveSearchInputProps{\n\t\t\t\tID:     \"active-search-example-input\",\n\t\t\t\tURL:    \"/active-search\",\n\t\t\t\tTarget: fmt.Sprintf(\"#%s \u003e tbody\", id),\n\t\t\t\tInputProps: components.InputProps{\n\t\t\t\t\tIcon:        searchIcon(),\n\t\t\t\t\tName:        \"active-search-example\",\n\t\t\t\t\tType:        \"search\",\n\t\t\t\t\tPlaceholder: \"Filter table...\",\n\t\t\t\t\tSize:        \"sm\",\n\t\t\t\t},\n\t\t\t})\n\t\t@components.Table(\n\t\t\theaders,\n\t\t\tactiveSearchTableDataComponents(),\n\t\t\ttempl.Attributes{\"id\": \"active-search-example-table\"},\n\t\t)\n\t\u003c/div\u003e\n}\n\ntempl searchIcon() {\n\t\u003csvg\n\t\tclass=\"w-5 h-5\"\n\t\tviewBox=\"0 0 32 32\"\n\t\tversion=\"1.1\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\txmlns:xlink=\"http://www.w3.org/1999/xlink\"\n\t\txmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\"\n\t\u003e\n\t\t\u003cg stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\"\u003e\n\t\t\t\u003cg class=\"fill-base-content/60\" id=\"Icon-Set\" sketch:type=\"MSLayerGroup\" transform=\"translate(-256.000000, -1139.000000)\"\u003e\n\t\t\t\t\u003cpath d=\"M269.46,1163.45 C263.17,1163.45 258.071,1158.44 258.071,1152.25 C258.071,1146.06 263.17,1141.04 269.46,1141.04 C275.75,1141.04 280.85,1146.06 280.85,1152.25 C280.85,1158.44 275.75,1163.45 269.46,1163.45 L269.46,1163.45 Z M287.688,1169.25 L279.429,1161.12 C281.591,1158.77 282.92,1155.67 282.92,1152.25 C282.92,1144.93 276.894,1139 269.46,1139 C262.026,1139 256,1144.93 256,1152.25 C256,1159.56 262.026,1165.49 269.46,1165.49 C272.672,1165.49 275.618,1164.38 277.932,1162.53 L286.224,1170.69 C286.629,1171.09 287.284,1171.09 287.688,1170.69 C288.093,1170.3 288.093,1169.65 287.688,1169.25 L287.688,1169.25 Z\" id=\"search\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n\t\t\t\u003c/g\u003e\n\t\t\u003c/g\u003e\n\t\u003c/svg\u003e\n}\n\nfunc activeSearchTableDataComponents() []templ.Component {\n\tcoms := make([]templ.Component, len(ActiveSearchTableData))\n\tfor i := range ActiveSearchTableData {\n\t\tcoms[i] = ActiveSearchTableRow(\n\t\t\tActiveSearchTableData[i].FirstName,\n\t\t\tActiveSearchTableData[i].LastName,\n\t\t\tActiveSearchTableData[i].Email)\n\t}\n\treturn coms\n}\n\nvar ActiveSearchTableData = []struct {\n\tFirstName string\n\tLastName  string\n\tEmail     string\n}{\n\t{FirstName: \"John\", LastName: \"Smith\", Email: \"john.smith@email.com\"},\n\t{FirstName: \"Emily\", LastName: \"Johnson\", Email: \"emily.johnson@email.com\"},\n\t{FirstName: \"Michael\", LastName: \"Brown\", Email: \"michael.brown@email.com\"},\n\t{FirstName: \"Jessica\", LastName: \"Williams\", Email: \"jessica.williams@email.com\"},\n\t{FirstName: \"David\", LastName: \"Jones\", Email: \"david.jones@email.com\"},\n\t{FirstName: \"Sarah\", LastName: \"Miller\", Email: \"sarah.miller@email.com\"},\n\t{FirstName: \"Christopher\", LastName: \"Davis\", Email: \"chris.davis@email.com\"},\n\t{FirstName: \"Amanda\", LastName: \"Wilson\", Email: \"amanda.wilson@email.com\"},\n\t{FirstName: \"James\", LastName: \"Taylor\", Email: \"james.taylor@email.com\"},\n\t{FirstName: \"Laura\", LastName: \"Moore\", Email: \"laura.moore@email.com\"},\n}\n\ntempl ActiveSearchTableRows(rows []templ.Component) {\n\tfor _, r := range rows {\n\t\t@r\n\t}\n}\n\ntempl ActiveSearchTableRow(firstName, lastName, email string) {\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e{ firstName }\u003c/td\u003e\n\t\t\u003ctd\u003e{ lastName }\u003c/td\u003e\n\t\t\u003ctd\u003e{ email }\u003c/td\u003e\n\t\u003c/tr\u003e\n}\n```",
      "handler": "```go\nfunc GetActiveSearchExample(c echo.Context) error {\n\ttime.Sleep(500 * time.Millisecond)\n\n\tsearch := strings.ToLower(strings.TrimSpace(c.FormValue(\"active-search-example\")))\n\n\tout := make([]templ.Component, 0, len(examples.ActiveSearchTableData))\n\n\tfor _, rowData := range examples.ActiveSearchTableData {\n\t\tif search == \"\" || (strings.Contains(strings.ToLower(rowData.FirstName), search) ||\n\t\t\tstrings.Contains(strings.ToLower(rowData.LastName), search) ||\n\t\t\tstrings.Contains(strings.ToLower(rowData.Email), search)) {\n\t\t\tout = append(out, examples.ActiveSearchTableRow(\n\t\t\t\trowData.FirstName, rowData.LastName, rowData.Email))\n\t\t}\n\t}\n\n\treturn render(c, http.StatusOK, examples.ActiveSearchTableRows(out))\n}\n\n```",
      "title": "Active search input for a table"
    }
  ],
  "alert": [
    {
      "name": "AlertInfoExample",
      "code": "```go\ntempl AlertInfoExample() {\n\t\u003cdiv class=\"max-w-md mx-auto pt-4\"\u003e\n\t\t@components.AlertInfo(\n\t\t\t\"Your profile has been successfully updated. Please review your changes.\",\n\t\t)\n\t\u003c/div\u003e\n}\n\n```",
      "title": "Info-type alert"
    },
    {
      "name": "AlertSuccessExample",
      "code": "```go\ntempl AlertSuccessExample() {\n\t\u003cdiv class=\"max-w-md mx-auto pt-4\"\u003e\n\t\t@components.AlertSuccess(\n\t\t\t\"Your payment was processed successfully! Thank you for your purchase.\",\n\t\t) {\n\t\t\t\u003cbutton class=\"btn btn-sm\"\u003eOK\u003c/button\u003e\n\t\t}\n\t\u003c/div\u003e\n}\n\n```",
      "title": "Success-type alert"
    },
    {
      "name": "AlertWarningExample",
      "code": "```go\ntempl AlertWarningExample() {\n\t\u003cdiv class=\"max-w-md mx-auto pt-4\"\u003e\n\t\t@components.AlertWarning(\n\t\t\t\"Your password will expire in 7 days. Please update it to avoid any disruptions.\",\n\t\t)\n\t\u003c/div\u003e\n}\n\n```",
      "title": "Warning-type alert"
    },
    {
      "name": "AlertErrorExample",
      "code": "```go\ntempl AlertErrorExample() {\n\t\u003cdiv class=\"max-w-md mx-auto pt-4\"\u003e\n\t\t@components.AlertError(\n\t\t\t\"Failed to connect to the server. Please try again later or contact support if the issue persists.\",\n\t\t) {\n\t\t\t\u003cbutton class=\"btn btn-sm\"\u003eOK\u003c/button\u003e\n\t\t}\n\t\u003c/div\u003e\n}\n```",
      "title": "Error-type alert"
    }
  ],
  "anchor": [
    {
      "name": "BasicAnchor",
      "code": "```go\ntempl BasicAnchor() {\n\t@components.Anchor(components.AnchorProps{\n\t\tLabel: \"Basic anchor\",\n\t\tClass: \"link\",\n\t})\n}\n\n```",
      "title": "Basic anchor"
    },
    {
      "name": "PrimaryAnchor",
      "code": "```go\ntempl PrimaryAnchor() {\n\t@components.Anchor(components.AnchorProps{\n\t\tLabel: \"Primary anchor\",\n\t\tClass: \"link link-primary\",\n\t})\n}\n\n```",
      "title": "Primary anchor"
    },
    {
      "name": "AnchorWithIcon",
      "code": "```go\ntempl AnchorWithIcon() {\n\t@components.Anchor(components.AnchorProps{\n\t\tLabel:    \"GitHub profile\",\n\t\tLeftIcon: GithubIcon(),\n\t\tClass:    \"link\",\n\t})\n}\n\n```",
      "title": "Anchor with icon"
    },
    {
      "name": "SocialAnchors",
      "code": "```go\ntempl SocialAnchors() {\n\t\u003cdiv class=\"mx-auto\"\u003e\n\t\t\u003cdiv class=\"flex space-x-4\"\u003e\n\t\t\t@components.Anchor(components.AnchorProps{LeftIcon: XIcon()})\n\t\t\t@components.Anchor(components.AnchorProps{LeftIcon: YoutubeIcon()})\n\t\t\t@components.Anchor(components.AnchorProps{LeftIcon: FacebookIcon()})\n\t\t\t@components.Anchor(components.AnchorProps{LeftIcon: GithubIcon()})\n\t\t\t@components.Anchor(components.AnchorProps{LeftIcon: LinkedInIcon()})\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n\ntempl XIcon() {\n\t\u003csvg\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\tx=\"0px\"\n\t\ty=\"0px\"\n\t\tviewBox=\"0 0 50 50\"\n\t\tclass=\"h-6 w-6 fill-base-content/80 hover:fill-base-content inline-block mr-1\"\n\t\u003e\n\t\t\u003cpath d=\"M 5.9199219 6 L 20.582031 27.375 L 6.2304688 44 L 9.4101562 44 L 21.986328 29.421875 L 31.986328 44 L 44 44 L 28.681641 21.669922 L 42.199219 6 L 39.029297 6 L 27.275391 19.617188 L 17.933594 6 L 5.9199219 6 z M 9.7167969 8 L 16.880859 8 L 40.203125 42 L 33.039062 42 L 9.7167969 8 z\"\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n\ntempl YoutubeIcon() {\n\t\u003csvg\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\tviewBox=\"0 0 24 24\"\n\t\tclass=\"h-6 w-6 fill-base-content/80 hover:fill-base-content inline-block mr-1\"\n\t\u003e\n\t\t\u003cpath\n\t\t\td=\"M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z\"\n\t\t\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n\ntempl FacebookIcon() {\n\t\u003csvg\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\tviewBox=\"0 0 24 24\"\n\t\tclass=\"h-6 w-6 fill-base-content/80 hover:fill-base-content inline-block mr-1\"\n\t\u003e\n\t\t\u003cpath\n\t\t\td=\"M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z\"\n\t\t\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n\ntempl GithubIcon() {\n\t\u003csvg\n\t\tclass=\"h-6 w-6 inline-block mr-1\"\n\t\tviewBox=\"0 0 20 20\"\n\t\tversion=\"1.1\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\txmlns:xlink=\"http://www.w3.org/1999/xlink\"\n\t\u003e\n\t\t\u003cg stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\"\u003e\n\t\t\t\u003cg class=\"fill-base-content/80 hover:fill-base-content group-hover:fill-base-content\" id=\"Dribbble-Light-Preview\" transform=\"translate(-140.000000, -7559.000000)\"\u003e\n\t\t\t\t\u003cg id=\"icons\" transform=\"translate(56.000000, 160.000000)\"\u003e\n\t\t\t\t\t\u003cpath d=\"M94,7399 C99.523,7399 104,7403.59 104,7409.253 C104,7413.782 101.138,7417.624 97.167,7418.981 C96.66,7419.082 96.48,7418.762 96.48,7418.489 C96.48,7418.151 96.492,7417.047 96.492,7415.675 C96.492,7414.719 96.172,7414.095 95.813,7413.777 C98.04,7413.523 100.38,7412.656 100.38,7408.718 C100.38,7407.598 99.992,7406.684 99.35,7405.966 C99.454,7405.707 99.797,7404.664 99.252,7403.252 C99.252,7403.252 98.414,7402.977 96.505,7404.303 C95.706,7404.076 94.85,7403.962 94,7403.958 C93.15,7403.962 92.295,7404.076 91.497,7404.303 C89.586,7402.977 88.746,7403.252 88.746,7403.252 C88.203,7404.664 88.546,7405.707 88.649,7405.966 C88.01,7406.684 87.619,7407.598 87.619,7408.718 C87.619,7412.646 89.954,7413.526 92.175,7413.785 C91.889,7414.041 91.63,7414.493 91.54,7415.156 C90.97,7415.418 89.522,7415.871 88.63,7414.304 C88.63,7414.304 88.101,7413.319 87.097,7413.247 C87.097,7413.247 86.122,7413.234 87.029,7413.87 C87.029,7413.87 87.684,7414.185 88.139,7415.37 C88.139,7415.37 88.726,7417.2 91.508,7416.58 C91.513,7417.437 91.522,7418.245 91.522,7418.489 C91.522,7418.76 91.338,7419.077 90.839,7418.982 C86.865,7417.627 84,7413.783 84,7409.253 C84,7403.59 88.478,7399 94,7399\"\u003e\u003c/path\u003e\n\t\t\t\t\u003c/g\u003e\n\t\t\t\u003c/g\u003e\n\t\t\u003c/g\u003e\n\t\u003c/svg\u003e\n}\n\ntempl LinkedInIcon() {\n\t\u003csvg\n\t\tclass=\"h-6 w-6 fill-base-content/80 hover:fill-base-content inline-block mr-1\"\n\t\tviewBox=\"0 0 32 32\"\n\t\tversion=\"1.1\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\u003e\n\t\t\u003cpath d=\"M28.778 1.004h-25.56c-0.008-0-0.017-0-0.027-0-1.199 0-2.172 0.964-2.186 2.159v25.672c0.014 1.196 0.987 2.161 2.186 2.161 0.010 0 0.019-0 0.029-0h25.555c0.008 0 0.018 0 0.028 0 1.2 0 2.175-0.963 2.194-2.159l0-0.002v-25.67c-0.019-1.197-0.994-2.161-2.195-2.161-0.010 0-0.019 0-0.029 0h0.001zM9.9 26.562h-4.454v-14.311h4.454zM7.674 10.293c-1.425 0-2.579-1.155-2.579-2.579s1.155-2.579 2.579-2.579c1.424 0 2.579 1.154 2.579 2.578v0c0 0.001 0 0.002 0 0.004 0 1.423-1.154 2.577-2.577 2.577-0.001 0-0.002 0-0.003 0h0zM26.556 26.562h-4.441v-6.959c0-1.66-0.034-3.795-2.314-3.795-2.316 0-2.669 1.806-2.669 3.673v7.082h-4.441v-14.311h4.266v1.951h0.058c0.828-1.395 2.326-2.315 4.039-2.315 0.061 0 0.121 0.001 0.181 0.003l-0.009-0c4.5 0 5.332 2.962 5.332 6.817v7.855z\"\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n```",
      "title": "Socials anchors"
    }
  ],
  "avatar": [
    {
      "name": "MultipleAvatarSizes",
      "code": "```go\ntempl MultipleAvatarSizes() {\n\t\u003cdiv class=\"flex justify-center items-center space-x-4 pt-4\"\u003e\n\t\t@components.Avatar(components.AvatarProps{\n\t\t\tContainerClass: \"rounded w-8\", Source: \"/static/images/avatar.jpg\"})\n\t\t@components.Avatar(components.AvatarProps{\n\t\t\tContainerClass: \"rounded w-12\", Source: \"/static/images/avatar.jpg\"})\n\t\t@components.Avatar(components.AvatarProps{\n\t\t\tContainerClass: \"rounded w-16\", Source: \"/static/images/avatar.jpg\"})\n\t\t@components.Avatar(components.AvatarProps{\n\t\t\tContainerClass: \"rounded w-20\", Source: \"/static/images/avatar.jpg\"})\n\t\t@components.Avatar(components.AvatarProps{\n\t\t\tContainerClass: \"rounded w-24\", Source: \"/static/images/avatar.jpg\"})\n\t\u003c/div\u003e\n}\n\n```",
      "title": "Multiple avatar sizes"
    },
    {
      "name": "GroupOfAvatars",
      "code": "```go\ntempl GroupOfAvatars() {\n\t\u003cdiv class=\"flex justify-center items-center space-x-4 pt-4\"\u003e\n\t\t@components.AvatarGroup(\"-space-x-8\") {\n\t\t\t@components.Avatar(components.AvatarProps{\n\t\t\t\tContainerClass: \"rounded-full w-12\", Source: \"/static/images/avatar.jpg\"})\n\t\t\t@components.Avatar(components.AvatarProps{\n\t\t\t\tContainerClass: \"rounded-full w-12\", Source: \"/static/images/avatar.jpg\"})\n\t\t\t@components.Avatar(components.AvatarProps{\n\t\t\t\tContainerClass: \"rounded-full w-12\", Source: \"/static/images/avatar.jpg\"})\n\t\t\t@components.Avatar(components.AvatarProps{\n\t\t\t\tContainerClass: \"rounded-full w-12\", Source: \"/static/images/avatar.jpg\"})\n\t\t\t@components.Avatar(components.AvatarProps{\n\t\t\t\tContainerClass: \"rounded-full w-12\", Source: \"/static/images/avatar.jpg\"})\n\t\t}\n\t\u003c/div\u003e\n}\n\n```",
      "title": "Avatar group"
    },
    {
      "name": "OnlineAndOffline",
      "code": "```go\ntempl OnlineAndOffline() {\n\t\u003cdiv class=\"flex justify-center items-center space-x-4 pt-4\"\u003e\n\t\t@components.Avatar(components.AvatarProps{\n\t\t\tAvatarClass:    \"avatar-online\",\n\t\t\tContainerClass: \"rounded-full w-12\",\n\t\t\tSource:         \"/static/images/avatar.jpg\",\n\t\t})\n\t\t@components.Avatar(components.AvatarProps{\n\t\t\tAvatarClass:    \"avatar-offline\",\n\t\t\tContainerClass: \"rounded-full w-12\",\n\t\t\tSource:         \"/static/images/avatar.jpg\",\n\t\t})\n\t\u003c/div\u003e\n}\n```",
      "title": "Avatar with online/offline indicator"
    }
  ],
  "banner": [
    {
      "name": "BannerExample",
      "code": "```go\ntempl BannerExample() {\n\t@components.Banner(components.BannerProps{\n\t\tTitle: basicBannerTitle(),\n\t\tDescription: `Lorem ipsum dolor sit amet consectetur adipisicing elit. \nSapiente iure non, quia perspiciatis sed temporibus quos nihil, voluptatibus tempore \nplaceat ipsa est facilis, nobis illum in magni illo neque libero.`,\n\t}) {\n\t\t\u003ca class=\"btn btn-primary\"\u003e\n\t\t\tGet started\n\t\t\u003c/a\u003e\n\t\t\u003ca class=\"btn btn-neutral\"\u003e\n\t\t\tLearn more\n\t\t\u003c/a\u003e\n\t}\n}\n\ntempl basicBannerTitle() {\n\t\u003ch1 class=\"text-3xl font-extrabold sm:text-5xl\"\u003e\n\t\tLorem ipsum dolor.\n\t\t\u003cstrong class=\"font-extrabold text-primary sm:block\"\u003eSit amet consectetur. \u003c/strong\u003e\n\t\u003c/h1\u003e\n}\n```"
    }
  ],
  "breadcrumbs": [
    {
      "name": "BreadcrumbsExample",
      "code": "```go\ntempl BreadcrumbsExample() {\n\t\u003cdiv class=\"flex justify-center items-center pt-4\"\u003e\n\t\t@components.Breadcrumbs(\n\t\t\tcomponents.BreadcrumbsProps{\n\t\t\t\t{\n\t\t\t\t\tLabel: \"Laptops\",\n\t\t\t\t\tAttrs: templ.Attributes{\"href\": \"/laptops\", \"class\": \"link\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tLabel: \"Macbooks\",\n\t\t\t\t\tAttrs: templ.Attributes{\"href\": \"/laptops/macbooks\", \"class\": \"link\"},\n\t\t\t\t},\n\t\t\t\t{Label: \"Macbook Pro 14\"},\n\t\t\t},\n\t\t)\n\t\u003c/div\u003e\n}\n```"
    }
  ],
  "card": [
    {
      "name": "BasicCard",
      "code": "```go\ntempl BasicCard() {\n\t\u003cdiv class=\"flex justify-center items-center py-4\"\u003e\n\t\t@components.Card(\n\t\t\tcomponents.CardProps{\n\t\t\t\tTitle:   \"This is a card\",\n\t\t\t\tContent: \"And this is the card's content.\",\n\t\t\t\tClass:   \"bg-base-100 w-96 shadow-xl\",\n\t\t\t},\n\t\t)\n\t\u003c/div\u003e\n}\n\n```",
      "title": "Basic card"
    },
    {
      "name": "BasicCardWithImage",
      "code": "```go\ntempl BasicCardWithImage() {\n\t\u003cdiv class=\"flex justify-center items-center py-4\"\u003e\n\t\t@components.Card(\n\t\t\tcomponents.CardProps{\n\t\t\t\tTitle:   \"Card with image\",\n\t\t\t\tContent: \"Card with image content\",\n\t\t\t\tSource:  \"/static/images/avatar.jpg\",\n\t\t\t\tAlt:     \"avatar image\",\n\t\t\t\tClass:   \"card-bordered bg-base-100 w-96 shadow-xl\",\n\t\t\t},\n\t\t) {\n\t\t\t\u003cbutton class=\"btn btn-sm btn-primary\"\u003eContact\u003c/button\u003e\n\t\t}\n\t\u003c/div\u003e\n}\n```",
      "title": "Card with image"
    }
  ],
  "carousel": [
    {
      "name": "CarouselExample",
      "code": "```go\ntempl CarouselExample() {\n\t\u003cdiv class=\"max-h-80 pt-4 max-w-screen-md\"\u003e\n\t\t@components.Carousel(\n\t\t\tcomponents.CarouselProps{\n\t\t\t\t{Source: \"/static/images/avatar.jpg\", Alt: \"avatar image\"},\n\t\t\t\t{Source: \"/static/images/avatar.jpg\", Alt: \"avatar image\"},\n\t\t\t\t{Source: \"/static/images/avatar.jpg\", Alt: \"avatar image\"},\n\t\t\t\t{Source: \"/static/images/avatar.jpg\", Alt: \"avatar image\"},\n\t\t\t\t{Source: \"/static/images/avatar.jpg\", Alt: \"avatar image\"},\n\t\t\t\t{Source: \"/static/images/avatar.jpg\", Alt: \"avatar image\"},\n\t\t\t},\n\t\t)\n\t\u003c/div\u003e\n}\n```"
    }
  ],
  "chat": [
    {
      "name": "BasicChat",
      "code": "```go\ntempl BasicChat() {\n\t\u003cdiv class=\"w-full max-w-screen-sm rounded-box mx-auto border border-base-content/30 p-4\"\u003e\n\t\t@components.Chat(components.ChatProps{\n\t\t\t{\n\t\t\t\tAvatarURL: \"/static/images/avatar.jpg\",\n\t\t\t\tSender:    \"Me\",\n\t\t\t\tTime:      time.Now().UTC().Add(-4 * time.Minute).Format(\"15:04:05\"),\n\t\t\t\tMessage: `I started learning how to cook more dishes from scratch, \nand it's been way more satisfying than I expected. Last night, I made homemade pasta!`,\n\t\t\t\tFooter:   \"✓✓\",\n\t\t\t\tLocation: \"start\",\n\t\t\t\tClass:    \"chat-bubble-primary\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tAvatarURL: \"/static/images/avatar-reverse.jpg\",\n\t\t\t\tSender:    \"Myself\",\n\t\t\t\tTime:      time.Now().UTC().Add(-2 * time.Minute).Format(\"15:04:05\"),\n\t\t\t\tMessage: `That's awesome! Homemade pasta is no joke—it's a workout, \ntoo! Did you use a pasta machine, or go for the classic rolling pin method?`,\n\t\t\t\tFooter:   \"✓✓\",\n\t\t\t\tLocation: \"end\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tAvatarURL: \"/static/images/avatar.jpg\",\n\t\t\t\tSender:    \"Me\",\n\t\t\t\tTime:      time.Now().UTC().Add(-1 * time.Minute).Format(\"15:04:05\"),\n\t\t\t\tMessage: `Went old-school with the rolling pin! Took forever, but it \nwas worth it. I made a simple marinara sauce to go with it, and honestly, it was better \nthan what I usually order.`,\n\t\t\t\tFooter:   \"✓✓\",\n\t\t\t\tLocation: \"start\",\n\t\t\t\tClass:    \"chat-bubble-primary\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tAvatarURL: \"/static/images/avatar-reverse.jpg\",\n\t\t\t\tSender:    \"Myself\",\n\t\t\t\tTime:      time.Now().UTC().Format(\"15:04:05\"),\n\t\t\t\tMessage: `Love it! Next up, you've got to try ravioli. It's a bit \nmore work, but filling them with something like ricotta and spinach makes it feel \nsuper fancy. You'll impress everyone!`,\n\t\t\t\tFooter:   \"✓✓\",\n\t\t\t\tLocation: \"end\",\n\t\t\t},\n\t\t})\n\t\u003c/div\u003e\n}\n```"
    }
  ],
  "checkbox": [
    {
      "name": "DifferentSizeCheckboxes",
      "code": "```go\ntempl DifferentSizeCheckboxes() {\n\t\u003cdiv class=\"flex flex-col space-y-4 mx-auto pt-4\"\u003e\n\t\t@components.Checkbox(\n\t\t\tcomponents.CheckboxProps{\n\t\t\t\tBefore:  \"Remember me\",\n\t\t\t\tName:    \"remember_me\",\n\t\t\t\tChecked: false,\n\t\t\t\tSize:    \"xs\",\n\t\t\t},\n\t\t)\n\t\t@components.Checkbox(\n\t\t\tcomponents.CheckboxProps{\n\t\t\t\tBefore:  \"Remember me\",\n\t\t\t\tName:    \"remember_me\",\n\t\t\t\tChecked: false,\n\t\t\t\tSize:    \"sm\",\n\t\t\t},\n\t\t)\n\t\t@components.Checkbox(\n\t\t\tcomponents.CheckboxProps{\n\t\t\t\tBefore:  \"Remember me\",\n\t\t\t\tName:    \"remember_me\",\n\t\t\t\tChecked: false,\n\t\t\t},\n\t\t)\n\t\t@components.Checkbox(\n\t\t\tcomponents.CheckboxProps{\n\t\t\t\tBefore:  \"Remember me\",\n\t\t\t\tName:    \"remember_me\",\n\t\t\t\tChecked: false,\n\t\t\t\tSize:    \"lg\",\n\t\t\t},\n\t\t)\n\t\t@components.Checkbox(\n\t\t\tcomponents.CheckboxProps{\n\t\t\t\tBefore:  \"Remember me\",\n\t\t\t\tName:    \"remember_me\",\n\t\t\t\tChecked: false,\n\t\t\t\tSize:    \"xl\",\n\t\t\t},\n\t\t)\n\t\u003c/div\u003e\n}\n\n```",
      "title": "Different size checkboxes"
    },
    {
      "name": "PrimaryCheckbox",
      "code": "```go\ntempl PrimaryCheckbox() {\n\t\u003cdiv class=\"mx-auto pt-4\"\u003e\n\t\t@components.Checkbox(\n\t\t\tcomponents.CheckboxProps{\n\t\t\t\tAfter:   \"Remember me\",\n\t\t\t\tName:    \"remember_me\",\n\t\t\t\tChecked: true,\n\t\t\t\tClass:   \"checkbox-primary\",\n\t\t\t},\n\t\t)\n\t\u003c/div\u003e\n}\n```",
      "title": "Primary color checkbox with label after"
    }
  ],
  "collapse": [
    {
      "name": "CollapseExample",
      "code": "```go\ntempl CollapseExample() {\n\t\u003cdiv class=\"flex justify-center items-center pt-4\"\u003e\n\t\t@components.Collapse(\n\t\t\tcomponents.CollapseProps{\n\t\t\t\tTitle:        \"Click me to show/hide content\",\n\t\t\t\tTitleClass:   \"text-xl font-medium\",\n\t\t\t\tClass:        \"collapse-plus bg-base-300\",\n\t\t\t\tContentClass: \"bg-base-200\",\n\t\t\t}) {\n\t\t\t\u003cdiv class=\"pt-4\"\u003e\n\t\t\t\t\u003cp\u003eCollapse content\u003c/p\u003e\n\t\t\t\u003c/div\u003e\n\t\t}\n\t\u003c/div\u003e\n}\n```",
      "title": "Basic collapse"
    }
  ],
  "combobox": [
    {
      "name": "BasicCombobox",
      "code": "```go\ntempl BasicCombobox() {\n\t\u003cdiv class=\"h-96\"\u003e\n\t\t\u003cform hx-post=\"/combobox-submit/example_combo\" class=\"space-x-4\"\u003e\n\t\t\t@components.Combobox(components.ComboboxProps{\n\t\t\t\tName:  \"example_combo\",\n\t\t\t\tLabel: \"Example\",\n\t\t\t\tURL:   \"/combobox/%s/%s\",\n\t\t\t\tOptions: []string{\n\t\t\t\t\t\"Thing 1\", \"Thing 2\", \"Thing 3\", \"Thing 4\", \"Thing 5\", \"Thing 6\", \"Thing 7\",\n\t\t\t\t},\n\t\t\t})\n\t\t\t\u003cbutton type=\"submit\" class=\"btn btn-sm btn-primary\"\u003eSubmit\u003c/button\u003e\n\t\t\t\u003cscript\u003e\n\t\t\t\t// update the form to only include half of the input values\n\t\t\t\t// corresponding to the combobox's name since it will contain enabled checkbox values as well\n\t\t\t\t((form) =\u003e {\n\t\t\t\t\tform.addEventListener(\"htmx:configRequest\", (evt) =\u003e {\n\t\t\t\t\t\tlet values = evt.detail.parameters[\"example_combo\"]\n\t\t\t\t\t\tif (values !== undefined) {\n\t\t\t\t\t\t\tevt.detail.parameters[\"example_combo\"] = values.slice(0, Math.floor(values.length / 2))\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t})(document.currentScript.parentElement)\n\t\t\t\u003c/script\u003e\n\t\t\u003c/form\u003e\n\t\u003c/div\u003e\n}\n```",
      "handler": "```go\nfunc PostCombobox(c echo.Context) error {\n\tname := c.Param(\"name\")\n\tvalue := c.Param(\"value\")\n\n\treturn render(c, http.StatusOK, components.ComboBadge(name, value))\n}\n\nfunc PostComboboxSubmit(c echo.Context) error {\n\turlValues, err := c.FormParams()\n\tif err != nil {\n\t\treturn newErrorToast(http.StatusUnprocessableEntity, \"unable to parse form data\")\n\t}\n\n\tname := c.Param(\"name\")\n\tcomboboxPostData := urlValues[name]\n\n\treturn renderInfoFade(c, http.StatusOK, comboboxPostData)\n}\n\n```"
    }
  ],
  "countdown": [
    {
      "name": "CountdownFullExample",
      "code": "```go\ntempl CountdownFullExample() {\n\t\u003cdiv class=\"flex justify-center items-center pt-4\"\u003e\n\t\t@components.Countdown(\n\t\t\tcomponents.CountdownProps{\n\t\t\t\tExpires: time.Now().UTC().Add(25*time.Hour + 10*time.Second),\n\t\t\t\tDays:    true,\n\t\t\t\tHours:   true,\n\t\t\t\tSeconds: true,\n\t\t\t\tMinutes: true,\n\t\t\t})\n\t\u003c/div\u003e\n}\n\n```"
    },
    {
      "name": "CountdownHoursExample",
      "code": "```go\ntempl CountdownHoursExample() {\n\t\u003cdiv class=\"flex justify-center items-center pt-4\"\u003e\n\t\t@components.Countdown(\n\t\t\tcomponents.CountdownProps{\n\t\t\t\tExpires: time.Now().UTC().Add(10*time.Hour + 10*time.Second),\n\t\t\t\tHours:   true,\n\t\t\t\tSeconds: true,\n\t\t\t\tMinutes: true,\n\t\t\t})\n\t\u003c/div\u003e\n}\n\n```"
    },
    {
      "name": "CountdownMinutesExample",
      "code": "```go\ntempl CountdownMinutesExample() {\n\t\u003cdiv class=\"flex justify-center items-center pt-4\"\u003e\n\t\t@components.Countdown(\n\t\t\tcomponents.CountdownProps{\n\t\t\t\tExpires: time.Now().UTC().Add(15*time.Minute + 10*time.Second),\n\t\t\t\tSeconds: true,\n\t\t\t\tMinutes: true,\n\t\t\t})\n\t\u003c/div\u003e\n}\n\n```"
    },
    {
      "name": "CountdownSecondsExample",
      "code": "```go\ntempl CountdownSecondsExample() {\n\t\u003cdiv class=\"flex justify-center items-center pt-4\"\u003e\n\t\t@components.Countdown(\n\t\t\tcomponents.CountdownProps{\n\t\t\t\tExpires: time.Now().UTC().Add(20 * time.Second),\n\t\t\t\tSeconds: true,\n\t\t\t})\n\t\u003c/div\u003e\n}\n```"
    }
  ],
  "date_picker": [
    {
      "name": "BasicDatePicker",
      "code": "```go\ntempl BasicDatePicker() {\n\t{{ now := time.Now().UTC() }}\n\t@components.DatePicker(\n\t\tcomponents.DatePickerProps{\n\t\t\tYear:        now.Year(),\n\t\t\tMonth:       int(now.Month()),\n\t\t\tSelected:    now,\n\t\t\tStartOfWeek: time.Monday,\n\t\t},\n\t)\n}\n```",
      "handler": "```go\nfunc GetDatePicker(c echo.Context) error {\n\tyearStr := c.QueryParam(\"year\")\n\tmonthStr := c.QueryParam(\"month\")\n\n\tyear, yErr := strconv.Atoi(yearStr)\n\tmonth, mErr := strconv.Atoi(monthStr)\n\tif month \u003e 12 {\n\t\tyear += 1\n\t\tmonth = 1\n\t}\n\tif month \u003c 1 {\n\t\tyear -= 1\n\t\tmonth = 12\n\t}\n\n\tif yErr != nil || mErr != nil {\n\t\treturn newErrorToast(http.StatusUnprocessableEntity, \"Invalid year or month\")\n\t}\n\n\tvar selected time.Time\n\tnow := time.Now().UTC()\n\tif year == now.Year() \u0026\u0026 time.Month(month) == now.Month() {\n\t\tselected = now\n\t}\n\n\treturn render(\n\t\tc,\n\t\thttp.StatusOK,\n\t\tcomponents.DatePicker(\n\t\t\tcomponents.DatePickerProps{\n\t\t\t\tYear:        year,\n\t\t\t\tMonth:       month,\n\t\t\t\tSelected:    selected,\n\t\t\t\tStartOfWeek: time.Monday,\n\t\t\t}),\n\t)\n}\n\nfunc PostDatePickerSelectDay(c echo.Context) error {\n\tvalue := c.FormValue(\"date\")\n\td, err := time.Parse(\"2006-01-02\", value)\n\tif err != nil {\n\t\treturn newErrorToast(\n\t\t\thttp.StatusUnprocessableEntity,\n\t\t\tfmt.Sprintf(\"Invalid date '%s'\", value),\n\t\t)\n\t}\n\n\treturn render(c, http.StatusOK, components.DatePickerInput(d))\n}\n\nfunc GetDatePickerMonthPicker(c echo.Context) error {\n\tyearStr := c.QueryParam(\"year\")\n\n\tyear, yErr := strconv.Atoi(yearStr)\n\tif yErr != nil {\n\t\treturn newErrorToast(http.StatusUnprocessableEntity, \"Invalid year\")\n\t}\n\n\tdpp := components.DatePickerProps{\n\t\tYear: year,\n\t}\n\n\treturn render(c, http.StatusOK, components.DatePickerMonthPicker(dpp))\n}\n\nfunc GetDatePickerYearPicker(c echo.Context) error {\n\tyearStr := c.QueryParam(\"year\")\n\n\tyear, yErr := strconv.Atoi(yearStr)\n\tif yErr != nil {\n\t\treturn newErrorToast(http.StatusUnprocessableEntity, \"Invalid year\")\n\t}\n\n\tdpp := components.DatePickerProps{\n\t\tYear: year,\n\t}\n\n\treturn render(c, http.StatusOK, components.DatePickerYearPicker(dpp))\n}\n\n```"
    }
  ],
  "diff": [
    {
      "name": "ImageDiff",
      "code": "```go\ntempl ImageDiff() {\n\t\u003cdiv class=\"flex mx-auto pt-4 min-h-[240px] sm:min-h-[300px] lg:min-h-[480px]\"\u003e\n\t\t@components.Diff(\n\t\t\tcomponents.DiffProps{\n\t\t\t\tWidth:  16,\n\t\t\t\tHeight: 19,\n\t\t\t\tImage1: components.DiffImage{\n\t\t\t\t\tSource: \"/static/images/diff1.png\", Alt: \"diff image 1\",\n\t\t\t\t},\n\t\t\t\tImage2: components.DiffImage{\n\t\t\t\t\tSource: \"/static/images/diff2.png\", Alt: \"diff image 2\",\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t\u003c/div\u003e\n}\n```"
    }
  ],
  "drawer": [
    {
      "name": "BasicDrawer",
      "code": "```go\ntempl BasicDrawer() {\n\t\u003cdiv class=\"w-full h-[400px] flex flex-wrap items-center justify-center overflow-x-hidden\"\u003e\n\t\t@DrawerPreview(DrawerExampleToggle(), DrawerExampleMenu())\n\t\u003c/div\u003e\n}\n\ntempl DrawerPreview(toggle templ.Component, sidebar templ.Component) {\n\t\u003cdiv class=\"drawer h-[400px]\"\u003e\n\t\t\u003cinput id=\"my-drawer\" type=\"checkbox\" class=\"drawer-toggle\"/\u003e\n\t\t\u003cdiv class=\"flex flex-col items-center justify-center drawer-content\"\u003e\n\t\t\t{ children... }\n\t\t\t\u003clabel for=\"my-drawer\" class=\"btn btn-primary drawer-button\"\u003e\n\t\t\t\t@toggle\n\t\t\t\u003c/label\u003e\n\t\t\u003c/div\u003e\n\t\t\u003cdiv class=\"drawer-side h-full absolute\"\u003e\n\t\t\t\u003clabel for=\"my-drawer\" aria-label=\"close sidebar\" class=\"drawer-overlay\"\u003e\u003c/label\u003e\n\t\t\t\u003cul class=\"menu bg-base-200 text-base-content min-h-full w-60 md:w-80 p-4\"\u003e\n\t\t\t\t@sidebar\n\t\t\t\u003c/ul\u003e\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n\ntempl DrawerExampleToggle() {\n\t\u003cspan\u003eClick me\u003c/span\u003e\n}\n\ntempl DrawerExampleMenu() {\n\t@components.MenuItem(components.MenuItemProps{Label: \"Section 1\", Attrs: templ.Attributes{\"class\": \"menu-title\"}})\n\t@components.MenuItem(components.MenuItemProps{Label: \"Section 2\", Attrs: templ.Attributes{\"class\": \"menu-title\"}}) {\n\t\t@components.MenuItem(components.MenuItemProps{Label: \"2.1\"}) {\n\t\t\t@components.MenuItem(components.MenuItemProps{Label: \"2.1.1\"})\n\t\t\t@components.MenuItem(components.MenuItemProps{Label: \"2.1.2\"})\n\t\t}\n\t\t@components.MenuItem(components.MenuItemProps{Label: \"2.2\"}) {\n\t\t\t@components.MenuItem(components.MenuItemProps{Label: \"2.2.1\"})\n\t\t}\n\t\t@components.MenuItem(components.MenuItemProps{Label: \"2.3\"})\n\t}\n\t@components.MenuItem(components.MenuItemProps{Label: \"Section 3\", Attrs: templ.Attributes{\"class\": \"menu-title\"}}) {\n\t\t@components.MenuItem(components.MenuItemProps{Label: \"3.1\"})\n\t}\n}\n```"
    }
  ],
  "dropdown": [
    {
      "name": "BasicDropdown",
      "code": "```go\ntempl BasicDropdown() {\n\t\u003cdiv class=\"h-48\"\u003e\n\t\t@components.Dropdown(\n\t\t\tcomponents.DropdownProps{\n\t\t\t\tLabel: \"Dropdown label\",\n\t\t\t\tItems: []components.DropdownItem{\n\t\t\t\t\t{Label: \"Item 1\"},\n\t\t\t\t\t{Label: \"Item 2\"},\n\t\t\t\t\t{Label: \"Item 3\"},\n\t\t\t\t},\n\t\t\t\tListClass: \"bg-base-200 rounded-box z-50 w-52 p-2 shadow-sm\",\n\t\t\t},\n\t\t)\n\t\u003c/div\u003e\n}\n```"
    }
  ],
  "fab": [
    {
      "name": "BasicFAB",
      "code": "```go\ntempl BasicFAB() {\n\t\u003cdiv class=\"h-68 relative\"\u003e\n\t\t@components.FAB(\n\t\t\tcomponents.FABProps{\n\t\t\t\tClass:       \"absolute z-1\", // !! preview purpose only\n\t\t\t\tToggle:      \"F\",\n\t\t\t\tToggleClass: \"btn-lg btn-circle\",\n\t\t\t}) {\n\t\t\t\u003cbutton class=\"btn btn-lg btn-circle\"\u003eA\u003c/button\u003e\n\t\t\t\u003cbutton class=\"btn btn-lg btn-circle\"\u003eB\u003c/button\u003e\n\t\t\t\u003cbutton class=\"btn btn-lg btn-circle\"\u003eC\u003c/button\u003e\n\t\t}\n\t\u003c/div\u003e\n}\n\n```"
    },
    {
      "name": "FABWithSVGButtons",
      "code": "```go\ntempl FABWithSVGButtons() {\n\t\u003cdiv class=\"h-68 relative\"\u003e\n\t\t@components.FAB(\n\t\t\tcomponents.FABProps{\n\t\t\t\tClass:       \"absolute z-1\", // !! preview purpose only\n\t\t\t\tToggle:      fabSVGToggle(),\n\t\t\t\tToggleClass: \"btn-lg btn-circle\",\n\t\t\t}) {\n\t\t\t@fabSVGVoiceButton()\n\t\t\t@fabSVGImageButton()\n\t\t\t@fabSVGCameraButton()\n\t\t}\n\t\u003c/div\u003e\n}\n\ntempl fabSVGToggle() {\n\t\u003csvg\n\t\taria-label=\"New\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\tfill=\"none\"\n\t\tviewBox=\"0 0 24 24\"\n\t\tstroke-width=\"2\"\n\t\tstroke=\"currentColor\"\n\t\tclass=\"size-6\"\n\t\u003e\n\t\t\u003cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 4.5v15m7.5-7.5h-15\"\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n\ntempl fabSVGVoiceButton() {\n\t\u003cbutton class=\"btn btn-lg btn-circle\"\u003e\n\t\t\u003csvg\n\t\t\taria-label=\"Camera\"\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tfill=\"none\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tstroke-width=\"1.5\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tclass=\"size-6\"\n\t\t\u003e\n\t\t\t\u003cpath\n\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\td=\"M6.827 6.175A2.31 2.31 0 0 1 5.186 7.23c-.38.054-.757.112-1.134.175C2.999 7.58 2.25 8.507 2.25 9.574V18a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9.574c0-1.067-.75-1.994-1.802-2.169a47.865 47.865 0 0 0-1.134-.175 2.31 2.31 0 0 1-1.64-1.055l-.822-1.316a2.192 2.192 0 0 0-1.736-1.039 48.774 48.774 0 0 0-5.232 0 2.192 2.192 0 0 0-1.736 1.039l-.821 1.316Z\"\n\t\t\t\u003e\u003c/path\u003e\n\t\t\t\u003cpath\n\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\td=\"M16.5 12.75a4.5 4.5 0 1 1-9 0 4.5 4.5 0 0 1 9 0ZM18.75 10.5h.008v.008h-.008V10.5Z\"\n\t\t\t\u003e\u003c/path\u003e\n\t\t\u003c/svg\u003e\n\t\u003c/button\u003e\n}\n\ntempl fabSVGImageButton() {\n\t\u003cbutton class=\"btn btn-lg btn-circle\"\u003e\n\t\t\u003csvg\n\t\t\taria-label=\"Gallery\"\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tfill=\"none\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tstroke-width=\"1.5\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tclass=\"size-6\"\n\t\t\u003e\n\t\t\t\u003cpath\n\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\td=\"m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z\"\n\t\t\t\u003e\u003c/path\u003e\n\t\t\u003c/svg\u003e\n\t\u003c/button\u003e\n}\n\ntempl fabSVGCameraButton() {\n\t\u003cbutton class=\"btn btn-lg btn-circle\"\u003e\n\t\t\u003csvg\n\t\t\taria-label=\"Voice\"\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tfill=\"none\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tstroke-width=\"1.5\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tclass=\"size-6\"\n\t\t\u003e\n\t\t\t\u003cpath\n\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\td=\"M12 18.75a6 6 0 0 0 6-6v-1.5m-6 7.5a6 6 0 0 1-6-6v-1.5m6 7.5v3.75m-3.75 0h7.5M12 15.75a3 3 0 0 1-3-3V4.5a3 3 0 1 1 6 0v8.25a3 3 0 0 1-3 3Z\"\n\t\t\t\u003e\u003c/path\u003e\n\t\t\u003c/svg\u003e\n\t\u003c/button\u003e\n}\n\n```",
      "title": "FAB with SVGs as toggle and content buttons"
    },
    {
      "name": "FABFlowerExample",
      "code": "```go\ntempl FABFlowerExample() {\n\t\u003cdiv class=\"h-68 relative\"\u003e\n\t\t@components.FAB(components.FABProps{\n\t\t\tClass:       \"fab-flower absolute z-1\", // !! absolute \u0026 z-1 preview purpose only\n\t\t\tToggle:      \"F\",\n\t\t\tToggleClass: \"btn btn-lg btn-circle\",\n\t\t\tMainAction:  fabFlowerMainAction(),\n\t\t}) {\n\t\t\t\u003cbutton class=\"btn btn-lg btn-circle\"\u003eA\u003c/button\u003e\n\t\t\t\u003cbutton class=\"btn btn-lg btn-circle\"\u003eB\u003c/button\u003e\n\t\t\t\u003cbutton class=\"btn btn-lg btn-circle\"\u003eC\u003c/button\u003e\n\t\t\t\u003cbutton class=\"btn btn-lg btn-circle\"\u003eD\u003c/button\u003e\n\t\t}\n\t\u003c/div\u003e\n}\n\ntempl fabFlowerMainAction() {\n\t\u003cbutton class=\"btn btn-lg btn-circle btn-primary\"\u003eM\u003c/button\u003e\n}\n```",
      "title": "FAB flower"
    }
  ],
  "features": [
    {
      "name": "FeaturesExample",
      "code": "```go\ntempl FeaturesExample() {\n\t@components.Features(\n\t\tcomponents.FeaturesProps{\n\t\t\tTitle: \"Discover our exclusive features\",\n\t\t\tFeatures: []components.FeatureProps{\n\t\t\t\t{\n\t\t\t\t\tIcon:        CustomizationIcon(),\n\t\t\t\t\tTitle:       \"Customization\",\n\t\t\t\t\tDescription: \"Tailor our product to suit your needs.\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIcon:        SecurityIcon(),\n\t\t\t\t\tTitle:       \"Security\",\n\t\t\t\t\tDescription: \"Your data is protected by the latest security measures.\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIcon:        SupportIcon(),\n\t\t\t\t\tTitle:       \"Support\",\n\t\t\t\t\tDescription: \"24/7 customer support for all your inquiries.\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIcon:        PerformanceIcon(),\n\t\t\t\t\tTitle:       \"Performance\",\n\t\t\t\t\tDescription: \"Experience blazing-fast performance with our product.\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIcon:  GlobalReachIcon(),\n\t\t\t\t\tTitle: \"Global reach\",\n\t\t\t\t\tDescription: `Tailor our product to suit your needs. Expand your reach \nwith our global network.`,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIcon:        CommunicationIcon(),\n\t\t\t\t\tTitle:       \"Communication\",\n\t\t\t\t\tDescription: \"Seamless communication for your team.\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t)\n}\n\ntempl CustomizationIcon() {\n\t\u003csvg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" class=\"w-8 mb-6 inline-block\" viewBox=\"0 0 32 32\"\u003e\n\t\t\u003cpath d=\"M28.068 12h-.128a.934.934 0 0 1-.864-.6.924.924 0 0 1 .2-1.01l.091-.091a2.938 2.938 0 0 0 0-4.147l-1.511-1.51a2.935 2.935 0 0 0-4.146 0l-.091.091A.956.956 0 0 1 20 4.061v-.129A2.935 2.935 0 0 0 17.068 1h-2.136A2.935 2.935 0 0 0 12 3.932v.129a.956.956 0 0 1-1.614.668l-.086-.091a2.935 2.935 0 0 0-4.146 0l-1.516 1.51a2.938 2.938 0 0 0 0 4.147l.091.091a.935.935 0 0 1 .185 1.035.924.924 0 0 1-.854.579h-.128A2.935 2.935 0 0 0 1 14.932v2.136A2.935 2.935 0 0 0 3.932 20h.128a.934.934 0 0 1 .864.6.924.924 0 0 1-.2 1.01l-.091.091a2.938 2.938 0 0 0 0 4.147l1.51 1.509a2.934 2.934 0 0 0 4.147 0l.091-.091a.936.936 0 0 1 1.035-.185.922.922 0 0 1 .579.853v.129A2.935 2.935 0 0 0 14.932 31h2.136A2.935 2.935 0 0 0 20 28.068v-.129a.956.956 0 0 1 1.614-.668l.091.091a2.935 2.935 0 0 0 4.146 0l1.511-1.509a2.938 2.938 0 0 0 0-4.147l-.091-.091a.935.935 0 0 1-.185-1.035.924.924 0 0 1 .854-.58h.128A2.935 2.935 0 0 0 31 17.068v-2.136A2.935 2.935 0 0 0 28.068 12ZM29 17.068a.933.933 0 0 1-.932.932h-.128a2.956 2.956 0 0 0-2.083 5.028l.09.091a.934.934 0 0 1 0 1.319l-1.511 1.509a.932.932 0 0 1-1.318 0l-.09-.091A2.957 2.957 0 0 0 18 27.939v.129a.933.933 0 0 1-.932.932h-2.136a.933.933 0 0 1-.932-.932v-.129a2.951 2.951 0 0 0-5.028-2.082l-.091.091a.934.934 0 0 1-1.318 0l-1.51-1.509a.934.934 0 0 1 0-1.319l.091-.091A2.956 2.956 0 0 0 4.06 18h-.128A.933.933 0 0 1 3 17.068v-2.136A.933.933 0 0 1 3.932 14h.128a2.956 2.956 0 0 0 2.083-5.028l-.09-.091a.933.933 0 0 1 0-1.318l1.51-1.511a.932.932 0 0 1 1.318 0l.09.091A2.957 2.957 0 0 0 14 4.061v-.129A.933.933 0 0 1 14.932 3h2.136a.933.933 0 0 1 .932.932v.129a2.956 2.956 0 0 0 5.028 2.082l.091-.091a.932.932 0 0 1 1.318 0l1.51 1.511a.933.933 0 0 1 0 1.318l-.091.091A2.956 2.956 0 0 0 27.94 14h.128a.933.933 0 0 1 .932.932Z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\t\u003cpath d=\"M16 9a7 7 0 1 0 7 7 7.008 7.008 0 0 0-7-7Zm0 12a5 5 0 1 1 5-5 5.006 5.006 0 0 1-5 5Z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n\ntempl SecurityIcon() {\n\t\u003csvg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" class=\"w-8 mb-6 inline-block\" viewBox=\"0 0 682.667 682.667\"\u003e\n\t\t\u003cdefs\u003e\n\t\t\t\u003cclipPath id=\"a\" clipPathUnits=\"userSpaceOnUse\"\u003e\n\t\t\t\t\u003cpath d=\"M0 512h512V0H0Z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\t\t\u003c/clipPath\u003e\n\t\t\u003c/defs\u003e\n\t\t\u003cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" stroke-width=\"40\" clip-path=\"url(#a)\" transform=\"matrix(1.33 0 0 -1.33 0 682.667)\"\u003e\n\t\t\t\u003cpath d=\"M256 492 60 410.623v-98.925C60 183.674 137.469 68.38 256 20c118.53 48.38 196 163.674 196 291.698v98.925z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\t\t\u003cpath d=\"M178 271.894 233.894 216 334 316.105\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\t\u003c/g\u003e\n\t\u003c/svg\u003e\n}\n\ntempl SupportIcon() {\n\t\u003csvg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" class=\"w-8 mb-6 inline-block\" viewBox=\"0 0 512.001 512.001\"\u003e\n\t\t\u003cpath d=\"M271.029 0c-33.091 0-61 27.909-61 61s27.909 61 61 61 60-27.909 60-61-26.909-61-60-61zm66.592 122c-16.485 18.279-40.096 30-66.592 30-26.496 0-51.107-11.721-67.592-30-14.392 15.959-23.408 36.866-23.408 60v15c0 8.291 6.709 15 15 15h151c8.291 0 15-6.709 15-15v-15c0-23.134-9.016-44.041-23.408-60zM144.946 460.404 68.505 307.149c-7.381-14.799-25.345-20.834-40.162-13.493l-19.979 9.897c-7.439 3.689-10.466 12.73-6.753 20.156l90 180c3.701 7.423 12.704 10.377 20.083 6.738l19.722-9.771c14.875-7.368 20.938-25.417 13.53-40.272zM499.73 247.7c-12.301-9-29.401-7.2-39.6 3.9l-82 100.8c-5.7 6-16.5 9.6-22.2 9.6h-69.901c-8.401 0-15-6.599-15-15s6.599-15 15-15h60c16.5 0 30-13.5 30-30s-13.5-30-30-30h-78.6c-7.476 0-11.204-4.741-17.1-9.901-23.209-20.885-57.949-30.947-93.119-22.795-19.528 4.526-32.697 12.415-46.053 22.993l-.445-.361-21.696 19.094L174.28 452h171.749c28.2 0 55.201-13.5 72.001-36l87.999-126c9.9-13.201 7.2-32.399-6.299-42.3z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n\ntempl PerformanceIcon() {\n\t\u003csvg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" class=\"w-8 mb-6 inline-block\" viewBox=\"0 0 24 24\"\u003e\n\t\t\u003cg fill-rule=\"evenodd\" clip-rule=\"evenodd\"\u003e\n\t\t\t\u003cpath d=\"M17.03 8.97a.75.75 0 0 1 0 1.06l-4.2 4.2a.75.75 0 0 1-1.154-.114l-1.093-1.639L8.03 15.03a.75.75 0 0 1-1.06-1.06l3.2-3.2a.75.75 0 0 1 1.154.114l1.093 1.639L15.97 8.97a.75.75 0 0 1 1.06 0z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\t\t\u003cpath d=\"M13.75 9.5a.75.75 0 0 1 .75-.75h2a.75.75 0 0 1 .75.75v2a.75.75 0 0 1-1.5 0v-1.25H14.5a.75.75 0 0 1-.75-.75z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\t\t\u003cpath d=\"M3.095 3.095C4.429 1.76 6.426 1.25 9 1.25h6c2.574 0 4.57.51 5.905 1.845C22.24 4.429 22.75 6.426 22.75 9v6c0 2.574-.51 4.57-1.845 5.905C19.571 22.24 17.574 22.75 15 22.75H9c-2.574 0-4.57-.51-5.905-1.845C1.76 19.571 1.25 17.574 1.25 15V9c0-2.574.51-4.57 1.845-5.905zm1.06 1.06C3.24 5.071 2.75 6.574 2.75 9v6c0 2.426.49 3.93 1.405 4.845.916.915 2.419 1.405 4.845 1.405h6c2.426 0 3.93-.49 4.845-1.405.915-.916 1.405-2.419 1.405-4.845V9c0-2.426-.49-3.93-1.405-4.845C18.929 3.24 17.426 2.75 15 2.75H9c-2.426 0-3.93.49-4.845 1.405z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\t\u003c/g\u003e\n\t\u003c/svg\u003e\n}\n\ntempl GlobalReachIcon() {\n\t\u003csvg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" class=\"w-8 mb-6 inline-block\" viewBox=\"0 0 504.69 504.69\"\u003e\n\t\t\u003cpath d=\"M252.343 262.673c-49.32 0-89.447-40.127-89.447-89.447s40.127-89.447 89.447-89.447 89.447 40.127 89.447 89.447-40.121 89.447-89.447 89.447zm0-158.235c-37.926 0-68.787 30.861-68.787 68.787s30.861 68.787 68.787 68.787 68.787-30.861 68.787-68.787-30.855-68.787-68.787-68.787z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\t\u003cpath d=\"M391.787 405.309c-5.645 0-10.253-4.54-10.325-10.201-.883-70.306-58.819-127.503-129.15-127.503-49.264 0-93.543 27.405-115.561 71.52-8.724 17.473-13.269 36.31-13.517 55.988-.072 5.702-4.757 10.273-10.459 10.201s-10.273-4.757-10.201-10.459c.289-22.814 5.568-44.667 15.691-64.955 25.541-51.164 76.907-82.95 134.047-82.95 81.581 0 148.788 66.349 149.81 147.905.072 5.702-4.494 10.392-10.201 10.459-.046-.005-.087-.005-.134-.005z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\t\u003cpath d=\"M252.343 463.751c-116.569 0-211.408-94.834-211.408-211.408 0-116.569 94.839-211.408 211.408-211.408 116.574 0 211.408 94.839 211.408 211.408 0 116.574-94.834 211.408-211.408 211.408zm0-402.156c-105.18 0-190.748 85.568-190.748 190.748s85.568 190.748 190.748 190.748 190.748-85.568 190.748-190.748S357.523 61.595 252.343 61.595zM71.827 90.07 14.356 32.599c-4.034-4.034-4.034-10.573 0-14.607 4.029-4.034 10.573-4.034 14.607 0l57.466 57.471c4.034 4.034 3.951 10.49 0 14.607-3.792 3.951-11.039 3.698-14.602 0z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\t\u003cpath d=\"M14.717 92.254a10.332 10.332 0 0 1-10.299-9.653L.023 15.751a10.317 10.317 0 0 1 2.929-7.908 10.2 10.2 0 0 1 7.851-3.089L77.56 7.796c5.697.258 10.108 5.093 9.85 10.79s-5.041 10.154-10.79 9.85l-55.224-2.521 3.641 55.327c.377 5.692-3.936 10.614-9.628 10.986a7.745 7.745 0 0 1-.692.026zm403.541-2.184c-4.256-3.796-4.034-10.573 0-14.607l58.116-58.116c4.034-4.034 10.573-4.034 14.607 0s4.034 10.573 0 14.607L432.864 90.07c-4.085 3.951-9.338 4.7-14.606 0z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\t\u003cpath d=\"M489.974 92.254a9.85 9.85 0 0 1-.687-.021c-5.697-.372-10.01-5.294-9.633-10.986l3.641-55.327-55.224 2.515c-5.511.238-10.526-4.147-10.79-9.85-.258-5.702 4.153-10.531 9.85-10.79l66.757-3.042c2.934-.134 5.79.992 7.851 3.089s3.12 4.974 2.929 7.908l-4.401 66.85c-.361 5.465-4.896 9.654-10.293 9.654zM11.711 489.339c-3.791-4.266-4.034-10.573 0-14.607l60.115-60.11c4.029-4.034 10.578-4.034 14.607 0 4.034 4.034 4.034 10.573 0 14.607l-60.115 60.11c-3.827 3.884-11.156 3.884-14.607 0z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\t\u003cpath d=\"M10.327 499.947a10.33 10.33 0 0 1-7.376-3.104 10.312 10.312 0 0 1-2.929-7.902l4.401-66.85c.372-5.697 5.191-10.036 10.986-9.633 5.692.377 10.005 5.294 9.628 10.986l-3.641 55.332 55.224-2.515c5.645-.191 10.531 4.153 10.79 9.85.258 5.697-4.153 10.526-9.85 10.79l-66.763 3.037c-.155.004-.31.009-.47.009zm465.639-13.01-57.708-57.708c-4.034-4.034-4.034-10.573 0-14.607s10.573-4.034 14.607 0l57.708 57.708c4.034 4.034 3.962 10.5 0 14.607-3.817 3.951-10.062 3.951-14.607 0z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\t\u003cpath d=\"M494.359 499.947c-.155 0-.315-.005-.47-.01l-66.757-3.042c-5.702-.263-10.108-5.088-9.85-10.79.263-5.702 5.113-9.984 10.79-9.85l55.219 2.515-3.641-55.332c-.372-5.692 3.941-10.609 9.633-10.986 5.625-.398 10.609 3.946 10.986 9.633l4.401 66.85a10.33 10.33 0 0 1-2.929 7.902 10.323 10.323 0 0 1-7.382 3.11z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n\ntempl CommunicationIcon() {\n\t\u003csvg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" class=\"w-8 mb-6 inline-block\" viewBox=\"0 0 682.667 682.667\"\u003e\n\t\t\u003cdefs\u003e\n\t\t\t\u003cclipPath id=\"a\" clipPathUnits=\"userSpaceOnUse\"\u003e\n\t\t\t\t\u003cpath d=\"M0 512h512V0H0Z\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\t\t\u003c/clipPath\u003e\n\t\t\u003c/defs\u003e\n\t\t\u003cg fill=\"none\" stroke=\"currentColor\" stroke-miterlimit=\"10\" stroke-width=\"30\" clip-path=\"url(#a)\" transform=\"matrix(1.33 0 0 -1.33 0 682.667)\"\u003e\n\t\t\t\u003cpath d=\"M226 15v60c0 16.568-13.432 30-30 30H76c-16.568 0-30-13.432-30-30V15Zm-45 165c0-24.853-20.147-45-45-45s-45 20.147-45 45 20.147 45 45 45 45-20.147 45-45ZM466 15v60c0 16.568-13.432 30-30 30H316c-16.568 0-30-13.432-30-30V15Zm-45 165c0-24.853-20.147-45-45-45s-45 20.147-45 45 20.147 45 45 45 45-20.147 45-45Zm-75 167v-50.294L286 347h-60.002L166 296.706V347h-15c-41.421 0-75 33.579-75 75s33.579 75 75 75h210c41.421 0 75-33.579 75-75s-33.579-75-75-75Zm-105 75h30m-90 0h30m90 0h30\" data-original=\"#000000\"\u003e\u003c/path\u003e\n\t\t\u003c/g\u003e\n\t\u003c/svg\u003e\n}\n```"
    }
  ],
  "file_input": [
    {
      "name": "DifferentSizeFileInputs",
      "code": "```go\ntempl DifferentSizeFileInputs() {\n\t@components.FileInput(components.FileInputProps{\n\t\tLabel: \"File upload\",\n\t\tSize:  \"xs\",\n\t})\n\t@components.FileInput(components.FileInputProps{\n\t\tLabel: \"File upload\",\n\t\tSize:  \"sm\",\n\t})\n\t@components.FileInput(components.FileInputProps{\n\t\tLabel: \"File upload\",\n\t})\n\t@components.FileInput(components.FileInputProps{\n\t\tLabel: \"File upload\",\n\t\tSize:  \"lg\",\n\t})\n\t@components.FileInput(components.FileInputProps{\n\t\tLabel: \"File upload\",\n\t\tSize:  \"xl\",\n\t})\n}\n```",
      "title": "Different size file inputs"
    }
  ],
  "footer": [
    {
      "name": "BasicFooterWithLinks",
      "code": "```go\ntempl BasicFooterWithLinks() {\n\t@components.Footer(\n\t\tcomponents.FooterProps{\n\t\t\tIcon:        FooterCompanyInfoIconExample(),\n\t\t\tName:        \"ACME Industries Ltd.\",\n\t\t\tDescription: \"Providing reliable tech since 1992\",\n\t\t\tAnchors: []components.AnchorProps{\n\t\t\t\t{LeftIcon: XIcon()},\n\t\t\t\t{LeftIcon: YoutubeIcon()},\n\t\t\t\t{LeftIcon: FacebookIcon()},\n\t\t\t},\n\t\t},\n\t) {\n\t\t@components.FooterNav(\n\t\t\t\"Services\",\n\t\t\t[]components.AnchorProps{\n\t\t\t\t{Label: \"Branding\"},\n\t\t\t\t{Label: \"Design\"},\n\t\t\t\t{Label: \"Marketing\"},\n\t\t\t\t{Label: \"Advertisement\"},\n\t\t\t},\n\t\t)\n\t\t@components.FooterNav(\n\t\t\t\"Company\",\n\t\t\t[]components.AnchorProps{\n\t\t\t\t{Label: \"About us\"},\n\t\t\t\t{Label: \"Contact\"},\n\t\t\t\t{Label: \"Jobs\"},\n\t\t\t\t{Label: \"Press kit\"},\n\t\t\t},\n\t\t)\n\t\t@components.FooterNav(\n\t\t\t\"Legal\",\n\t\t\t[]components.AnchorProps{\n\t\t\t\t{Label: \"Terms of use\"},\n\t\t\t\t{Label: \"Privacy policy\"},\n\t\t\t\t{Label: \"Cookie policy\"},\n\t\t\t},\n\t\t)\n\t}\n}\n\ntempl FooterCompanyInfoIconExample() {\n\t\u003csvg\n\t\twidth=\"24\"\n\t\theight=\"24\"\n\t\tviewBox=\"0 0 24 24\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\tfill-rule=\"evenodd\"\n\t\tclip-rule=\"evenodd\"\n\t\tclass=\"fill-current\"\n\t\u003e\n\t\t\u003cpath\n\t\t\td=\"M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z\"\n\t\t\u003e\u003c/path\u003e\n\t\u003c/svg\u003e\n}\n```"
    }
  ],
  "hero": [
    {
      "name": "BasicHero",
      "code": "```go\ntempl BasicHero() {\n\t\u003cdiv class=\"pt-4\"\u003e\n\t\t@components.Hero(components.HeroProps{\n\t\t\tSource: \"/static/images/avatar.jpg\",\n\t\t\tAlt:    \"hero avatar\",\n\t\t\tClass:  \"bg-base-200 min-h-[600px]\",\n\t\t}) {\n\t\t\t\u003cdiv class=\"prose\"\u003e\n\t\t\t\t\u003ch1\u003eLorem ipsum!\u003c/h1\u003e\n\t\t\t\t\u003cp\u003e\n\t\t\t\t\tLorem ipsum dolor sit, amet consectetur adipisicing elit.\n\t\t\t\t\tEx quibusdam dicta necessitatibus! Deleniti temporibus iure\n\t\t\t\t\tporro cupiditate dolorum modi voluptate perferendis velit\n\t\t\t\t\ttempora repudiandae expedita, impedit omnis vitae. Laborum,\n\t\t\t\t\tdignissimos?\n\t\t\t\t\u003c/p\u003e\n\t\t\t\t\u003cbutton class=\"btn btn-primary\"\u003eGet Started\u003c/button\u003e\n\t\t\t\u003c/div\u003e\n\t\t}\n\t\t@components.Hero(components.HeroProps{\n\t\t\tSource:  \"/static/images/avatar.jpg\",\n\t\t\tAlt:     \"hero avatar\",\n\t\t\tClass:   \"bg-base-200 min-h-[600px]\",\n\t\t\tReverse: true,\n\t\t}) {\n\t\t\t\u003cdiv class=\"prose\"\u003e\n\t\t\t\t\u003ch1\u003eLorem ipsum!\u003c/h1\u003e\n\t\t\t\t\u003cp\u003e\n\t\t\t\t\tLorem ipsum dolor sit, amet consectetur adipisicing elit.\n\t\t\t\t\tEx quibusdam dicta necessitatibus! Deleniti temporibus iure\n\t\t\t\t\tporro cupiditate dolorum modi voluptate perferendis velit\n\t\t\t\t\ttempora repudiandae expedita, impedit omnis vitae. Laborum,\n\t\t\t\t\tdignissimos?\n\t\t\t\t\u003c/p\u003e\n\t\t\t\t\u003cbutton class=\"btn btn-primary\"\u003eGet Started\u003c/button\u003e\n\t\t\t\u003c/div\u003e\n\t\t}\n\t\u003c/div\u003e\n}\n```"
    }
  ],
  "hover_3d_card": [
    {
      "name": "Hover3DCardExample",
      "code": "```go\ntempl Hover3DCardExample() {\n\t@components.Hover3DCard() {\n\t\t@components.Card(\n\t\t\tcomponents.CardProps{\n\t\t\t\tTitle:   \"Hover 3D Card\",\n\t\t\t\tContent: \"This is a hover 3D card. Move your mouse around the card.\",\n\t\t\t\tClass:   \"h-[200px] card-border\",\n\t\t\t},\n\t\t)\n\t}\n}\n```"
    }
  ],
  "infinite_scroll": [
    {
      "name": "InfiniteScrollTableExample",
      "code": "```go\ntempl InfiniteScrollTableExample() {\n\t@components.Table(\n\t\t[]templ.Component{components.PlainText(\"Name\"), components.PlainText(\"Email\")},\n\t\tinitialRows(),\n\t\tnil,\n\t)\n\t\u003cdiv class=\"flex justify-center\"\u003e\u003cspan id=\"spinner\" class=\"htmx-indicator loading loading-spinner\"\u003e\u003c/span\u003e\u003c/div\u003e\n}\n\nfunc initialRows() []templ.Component {\n\tdata := make([]templ.Component, 10)\n\tfor i := 0; i \u003c 10; i++ {\n\t\tdata[i] = components.InfiniteScrollRow(\"John Doe\", fmt.Sprintf(\"john.doe%d@email.com\", i), 0, i == 9)\n\t}\n\n\treturn data\n}\n```",
      "handler": "```go\nfunc GetInfiniteScrollExample(c echo.Context) error {\n\t// generate dummy row data\n\tdata := make([][]string, 0, 10)\n\tfor i := 0; i \u003c 10; i++ {\n\t\tdata = append(data, []string{\"John Doe\", fmt.Sprintf(\"john.doe%d@email.com\", i)})\n\t}\n\n\thasMore := true\n\n\trows := make([]templ.Component, 0, len(data))\n\tfor i := range data {\n\t\trows = append(\n\t\t\trows,\n\t\t\tcomponents.InfiniteScrollRow(data[i][0], data[i][1], 1, i+1 == 10 \u0026\u0026 hasMore),\n\t\t)\n\t}\n\n\treturn render(c, http.StatusOK, components.InfiniteScrollTable(rows))\n}\n\nfunc GetInfiniteScrollExampleRows(c echo.Context) error {\n\t// short delay for loading indicator\n\ttime.Sleep(500 * time.Millisecond)\n\n\tpageStr := c.QueryParam(\"page\")\n\tpage, err := strconv.Atoi(pageStr)\n\tif err != nil {\n\t\treturn newErrorToast(\n\t\t\thttp.StatusUnprocessableEntity,\n\t\t\tfmt.Sprintf(\"invalid page '%s'\", pageStr),\n\t\t)\n\t}\n\n\t// generate dummy date for the page\n\tdata := make([][]string, 0, 10)\n\tfor i := (page - 1) * 10; i \u003c (page-1)*10+10; i++ {\n\t\tdata = append(data, []string{\"John Doe\", fmt.Sprintf(\"john.doe%d@email.com\", i)})\n\t}\n\n\thasMore := len(data) == 10 \u0026\u0026 page \u003c 10\n\n\trows := make([]templ.Component, 0, len(data))\n\tfor i := range data {\n\t\trows = append(\n\t\t\trows,\n\t\t\tcomponents.InfiniteScrollRow(data[i][0], data[i][1], page, i+1 == 10 \u0026\u0026 hasMore),\n\t\t)\n\t}\n\n\treturn render(c, http.StatusOK, components.InfiniteScrollRows(rows))\n}\n\n```"
    }
  ],
  "input": [
    {
      "name": "DifferentSizeInputs",
      "code": "```go\ntempl DifferentSizeInputs() {\n\t@components.Input(components.InputProps{\n\t\tLabel:       \"Name\",\n\t\tPlaceholder: \"Your name...\",\n\t\tSize:        \"xs\",\n\t})\n\t@components.Input(components.InputProps{\n\t\tLabel:       \"Name\",\n\t\tPlaceholder: \"Your name...\",\n\t\tSize:        \"sm\",\n\t})\n\t@components.Input(components.InputProps{\n\t\tLabel:       \"Name\",\n\t\tPlaceholder: \"Your name...\",\n\t})\n\t@components.Input(components.InputProps{\n\t\tLabel:       \"Name\",\n\t\tPlaceholder: \"Your name...\",\n\t\tSize:        \"lg\",\n\t})\n\t@components.Input(components.InputProps{\n\t\tLabel:       \"Name\",\n\t\tPlaceholder: \"Your name...\",\n\t\tSize:        \"xl\",\n\t})\n}\n\n```",
      "title": "Different size inputs"
    },
    {
      "name": "IntegerInput",
      "code": "```go\ntempl IntegerInput() {\n\t@components.Input(components.InputProps{\n\t\tName:        \"my_number\",\n\t\tType:        \"number\",\n\t\tPlaceholder: \"Give a number...\",\n\t})\n}\n\n```",
      "title": "Integer input"
    },
    {
      "name": "DecimalInput",
      "code": "```go\ntempl DecimalInput() {\n\t@components.Input(components.InputProps{\n\t\tName:        \"my_number\",\n\t\tType:        \"number\",\n\t\tPlaceholder: \"Give a decimal number...\",\n\t\tAttrs: templ.Attributes{\n\t\t\t\"min\":  \"0.00\",\n\t\t\t\"max\":  \"2.00\",\n\t\t\t\"step\": \"0.25\",\n\t\t},\n\t})\n}\n\n```",
      "title": "Decimal input"
    },
    {
      "name": "PasswordFieldWithValidator",
      "code": "```go\ntempl PasswordFieldWithValidator() {\n\t@components.Input(components.InputProps{\n\t\tName:          \"password\",\n\t\tType:          \"password\",\n\t\tPlaceholder:   \"Password\",\n\t\tRequired:      true,\n\t\tPattern:       `(?=.*(\\W|_))(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,255}`,\n\t\tValidatorHint: \"Must be at least 8 characters long, including a digit, lower- and uppercase letter, and a special character\",\n\t\tIcon:          keyIcon(),\n\t\tAttrs: templ.Attributes{\n\t\t\t\"minlength\": \"8\",\n\t\t\t\"maxlength\": \"255\",\n\t\t},\n\t})\n}\n\ntempl keyIcon() {\n\t\u003csvg class=\"fill-current/75 h-5 w-5\" viewBox=\"0 0 32 32\" id=\"icon\" xmlns=\"http://www.w3.org/2000/svg\"\u003e\n\t\t\u003cpath d=\"M21,2a8.9977,8.9977,0,0,0-8.6119,11.6118L2,24v6H8L18.3881,19.6118A9,9,0,1,0,21,2Zm0,16a7.0125,7.0125,0,0,1-2.0322-.3022L17.821,17.35l-.8472.8472-3.1811,3.1812L12.4141,20,11,21.4141l1.3787,1.3786-1.5859,1.586L9.4141,23,8,24.4141l1.3787,1.3786L7.1716,28H4V24.8284l9.8023-9.8023.8472-.8474-.3473-1.1467A7,7,0,1,1,21,18Z\"\u003e\u003c/path\u003e\n\t\t\u003ccircle cx=\"22\" cy=\"10\" r=\"2\"\u003e\u003c/circle\u003e\n\t\t\u003crect class=\"fill-none\" id=\"_Transparent_Rectangle_\"\u003e\u003c/rect\u003e\n\t\u003c/svg\u003e\n}\n\n```",
      "title": "Password field with validator"
    },
    {
      "name": "EmailFieldWithValidator",
      "code": "```go\ntempl EmailFieldWithValidator() {\n\t@components.Input(components.InputProps{\n\t\tName:          \"email\",\n\t\tType:          \"email\",\n\t\tPlaceholder:   \"Email\",\n\t\tRequired:      true,\n\t\tPattern:       `^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$`,\n\t\tValidatorHint: \"Please enter a valid email address\",\n\t\tIcon:          emailIcon(),\n\t})\n}\n\ntempl emailIcon() {\n\t\u003csvg class=\"h-5 w-5\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"\u003e\n\t\t\u003cpath class=\"stroke-current/75\" d=\"M4 7.00005L10.2 11.65C11.2667 12.45 12.7333 12.45 13.8 11.65L20 7\" stroke-width=\"1\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\u003e\u003c/path\u003e\n\t\t\u003crect class=\"stroke-current/75\" x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" stroke-width=\"1\" stroke-linecap=\"round\"\u003e\u003c/rect\u003e\n\t\u003c/svg\u003e\n}\n\n```",
      "title": "Email field with validtor"
    },
    {
      "name": "SignUpFormExample",
      "code": "```go\ntempl SignUpFormExample() {\n\t\u003cdiv class=\"w-full max-w-xs mx-auto pt-12 pb-4\"\u003e\n\t\t\u003ch2 class=\"text-xl text-center mb-8\"\u003eSign Up\u003c/h2\u003e\n\t\t@OAuthButtons()\n\t\t\u003cdiv class=\"divider !my-6\"\u003eOR\u003c/div\u003e\n\t\t@SignUpForm(\n\t\t\t\"\", \"\",\n\t\t\t\"\", \"\",\n\t\t\t\"\", \"\",\n\t\t\t\"\", \"\",\n\t\t)\n\t\u003c/div\u003e\n}\n\ntempl SignUpForm(\n\tfirstName, firstNameError,\n\tlastName, lastNameError,\n\temail, emailError,\n\tpassword, passwordError string,\n) {\n\t\u003cdiv class=\"w-full max-w-xs mx-auto\"\u003e\n\t\t\u003cdiv\n\t\t\tclass=\"form space-y-1\"\n\t\t\thx-swap=\"outerHTML\"\n\t\t\u003e\n\t\t\t@components.Input(\n\t\t\t\tcomponents.InputProps{\n\t\t\t\t\tLabel:       \"First name\",\n\t\t\t\t\tName:        \"first_name\",\n\t\t\t\t\tPlaceholder: \"Your first name...\",\n\t\t\t\t\tValue:       firstName,\n\t\t\t\t\tError:       firstNameError,\n\t\t\t\t\tRequired:    true,\n\t\t\t\t\tAttrs: templ.Attributes{\n\t\t\t\t\t\t\"hx-post\": \"/validate/string/first_name?v=notempty\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t)\n\t\t\t@components.Input(\n\t\t\t\tcomponents.InputProps{\n\t\t\t\t\tLabel:       \"Last name\",\n\t\t\t\t\tName:        \"last_name\",\n\t\t\t\t\tPlaceholder: \"Your last name...\",\n\t\t\t\t\tValue:       lastName,\n\t\t\t\t\tError:       lastNameError,\n\t\t\t\t\tRequired:    true,\n\t\t\t\t\tAttrs: templ.Attributes{\n\t\t\t\t\t\t\"hx-post\": \"/validate/string/last_name?v=notempty\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t)\n\t\t\t@components.Input(\n\t\t\t\tcomponents.InputProps{\n\t\t\t\t\tLabel:       \"Email\",\n\t\t\t\t\tName:        \"email\",\n\t\t\t\t\tType:        \"email\",\n\t\t\t\t\tPlaceholder: \"Your email...\",\n\t\t\t\t\tValue:       email,\n\t\t\t\t\tError:       emailError,\n\t\t\t\t\tRequired:    true,\n\t\t\t\t\tAttrs: templ.Attributes{\n\t\t\t\t\t\t\"hx-post\": \"/validate/string/email?v=email\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t)\n\t\t\t@components.Input(\n\t\t\t\tcomponents.InputProps{\n\t\t\t\t\tLabel:         \"Password\",\n\t\t\t\t\tName:          \"password\",\n\t\t\t\t\tType:          \"password\",\n\t\t\t\t\tPlaceholder:   \"Your new password...\",\n\t\t\t\t\tRequired:      true,\n\t\t\t\t\tMinLength:     \"8\",\n\t\t\t\t\tMaxLength:     \"255\",\n\t\t\t\t\tPattern:       `(?=.*(\\W|_))(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,255}`,\n\t\t\t\t\tValidatorHint: \"Must be at least 8 characters long, including a digit, lower- and uppercase letter, and a special character\",\n\t\t\t\t\tAttrs: templ.Attributes{\n\t\t\t\t\t\t\"hx-post\": \"/validate/string/password?v=hasupper\u0026v=haslower\u0026v=hasdigit\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t)\n\t\t\t\u003cdiv class=\"pt-4\"\u003e\n\t\t\t\t\u003cbutton type=\"submit\" class=\"w-full btn btn-primary\"\u003e\n\t\t\t\t\tSign up\n\t\t\t\t\u003c/button\u003e\n\t\t\t\u003c/div\u003e\n\t\t\u003c/div\u003e\n\t\u003c/div\u003e\n}\n\ntempl OAuthButtons() {\n\t\u003cdiv class=\"w-full max-w-xs flex flex-col space-y-4 items-center justify-center\"\u003e\n\t\t@GoogleOAuthLink(\"\")\n\t\t@GithubOAuthLink(\"\")\n\t\u003c/div\u003e\n}\n\ntempl GoogleOAuthLink(href string) {\n\t\u003ca\n\t\thref={ templ.SafeURL(href) }\n\t\tclass=\"w-full max-w-sm py-3 flex justify-center gap-2 bg-gray-50 dark:bg-gray-900 hover:bg-gray-100 dark:hover:bg-black text-slate-950 dark:text-slate-50 rounded-box shadow-md transition-colors duration-300\"\n\t\u003e\n\t\t\u003csvg class=\"w-6 h-6\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\" fill=\"none\"\u003e\n\t\t\t\u003cpath d=\"M30.0014 16.3109C30.0014 15.1598 29.9061 14.3198 29.6998 13.4487H16.2871V18.6442H24.1601C24.0014 19.9354 23.1442 21.8798 21.2394 23.1864L21.2127 23.3604L25.4536 26.58L25.7474 26.6087C28.4458 24.1665 30.0014 20.5731 30.0014 16.3109Z\" fill=\"#4285F4\"\u003e\u003c/path\u003e\n\t\t\t\u003cpath d=\"M16.2863 29.9998C20.1434 29.9998 23.3814 28.7553 25.7466 26.6086L21.2386 23.1863C20.0323 24.0108 18.4132 24.5863 16.2863 24.5863C12.5086 24.5863 9.30225 22.1441 8.15929 18.7686L7.99176 18.7825L3.58208 22.127L3.52441 22.2841C5.87359 26.8574 10.699 29.9998 16.2863 29.9998Z\" fill=\"#34A853\"\u003e\u003c/path\u003e\n\t\t\t\u003cpath d=\"M8.15964 18.769C7.85806 17.8979 7.68352 16.9645 7.68352 16.0001C7.68352 15.0356 7.85806 14.1023 8.14377 13.2312L8.13578 13.0456L3.67083 9.64746L3.52475 9.71556C2.55654 11.6134 2.00098 13.7445 2.00098 16.0001C2.00098 18.2556 2.55654 20.3867 3.52475 22.2845L8.15964 18.769Z\" fill=\"#FBBC05\"\u003e\u003c/path\u003e\n\t\t\t\u003cpath d=\"M16.2864 7.4133C18.9689 7.4133 20.7784 8.54885 21.8102 9.4978L25.8419 5.64C23.3658 3.38445 20.1435 2 16.2864 2C10.699 2 5.8736 5.1422 3.52441 9.71549L8.14345 13.2311C9.30229 9.85555 12.5086 7.4133 16.2864 7.4133Z\" fill=\"#EB4335\"\u003e\u003c/path\u003e\n\t\t\u003c/svg\u003e\n\t\t\u003cspan\u003eSign in with Google\u003c/span\u003e\n\t\u003c/a\u003e\n}\n\ntempl GithubOAuthLink(href string) {\n\t\u003ca\n\t\thref={ templ.SafeURL(href) }\n\t\tclass=\"py-3 px-4 max-w-md flex justify-center items-center bg-gray-600 hover:bg-gray-700 focus:ring-gray-500 focus:ring-offset-gray-200 text-white w-full transition-colors duration-300 text-center text-base font-semibold shadow-md focus:outline-hidden focus:ring-2 focus:ring-offset-2 rounded-box\"\n\t\u003e\n\t\t\u003csvg class=\"w-6 h-6 mr-2\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" class=\"mr-2\" viewBox=\"0 0 1792 1792\"\u003e\n\t\t\t\u003cpath\n\t\t\t\td=\"M896 128q209 0 385.5 103t279.5 279.5 103 385.5q0 251-146.5 451.5t-378.5 277.5q-27 5-40-7t-13-30q0-3 .5-76.5t.5-134.5q0-97-52-142 57-6 102.5-18t94-39 81-66.5 53-105 20.5-150.5q0-119-79-206 37-91-8-204-28-9-81 11t-92 44l-38 24q-93-26-192-26t-192 26q-16-11-42.5-27t-83.5-38.5-85-13.5q-45 113-8 204-79 87-79 206 0 85 20.5 150t52.5 105 80.5 67 94 39 102.5 18q-39 36-49 103-21 10-45 15t-57 5-65.5-21.5-55.5-62.5q-19-32-48.5-52t-49.5-24l-20-3q-21 0-29 4.5t-5 11.5 9 14 13 12l7 5q22 10 43.5 38t31.5 51l10 23q13 38 44 61.5t67 30 69.5 7 55.5-3.5l23-4q0 38 .5 88.5t.5 54.5q0 18-13 30t-40 7q-232-77-378.5-277.5t-146.5-451.5q0-209 103-385.5t279.5-279.5 385.5-103zm-477 1103q3-7-7-12-10-3-13 2-3 7 7 12 9 6 13-2zm31 34q7-5-2-16-10-9-16-3-7 5 2 16 10 10 16 3zm30 45q9-7 0-19-8-13-17-6-9 5 0 18t17 7zm42 42q8-8-4-19-12-12-20-3-9 8 4 19 12 12 20 3zm57 25q3-11-13-16-15-4-19 7t13 15q15 6 19-6zm63 5q0-13-17-11-16 0-16 11 0 13 17 11 16 0 16-11zm58-10q-2-11-18-9-16 3-14 15t18 8 14-14z\"\n\t\t\t\u003e\u003c/path\u003e\n\t\t\u003c/svg\u003e\n\t\t\u003cspan\u003eSign in with GitHub\u003c/span\u003e\n\t\u003c/a\u003e\n}\n```",
      "title": "Sign up form with inline validation"
    }
  ],
  "lazy_load": [
    {
      "name": "LazyLoadExample",
      "code": "```go\ntempl LazyLoadExample() {\n\t@components.LazyLoad(\"/lazy-load\")\n}\n\ntempl LazyLoadResult() {\n\t\u003cdiv\n\t\tclass={\n\t\t\t\"bg-warning text-warning-content rounded-box\",\n\t\t\t\"w-28 h-28 flex justify-center items-center text-center\",\n\t\t}\n\t\u003e\n\t\tLAZY\n\t\t\u003cbr/\u003e\n\t\tLOAD\n\t\t\u003cbr/\u003e\n\t\tCOMPLETE\n\t\u003c/div\u003e\n}\n```",
      "handler": "```go\nfunc GetLazyLoadExample(c echo.Context) error {\n\ttime.Sleep(2 * time.Second)\n\n\treturn render(c, http.StatusOK, examples.LazyLoadResult())\n}\n\n```"
    }
  ],
  "menu": [
    {
      "name": "MenuExample",
      "code": "```go\ntempl MenuExample() {\n\t\u003cdiv class=\"w-full mx-auto max-w-xs pt-4\"\u003e\n\t\t@components.Menu(components.MenuProps{Title: \"Basic menu\", Class: \"w-52\"}) {\n\t\t\t@components.MenuItem(components.MenuItemProps{Label: \"Section 1\", Attrs: templ.Attributes{\"class\": \"menu-title\"}})\n\t\t\t@components.MenuItem(components.MenuItemProps{Label: \"Section 2\", Attrs: templ.Attributes{\"class\": \"menu-title\"}}) {\n\t\t\t\t@components.MenuItem(components.MenuItemProps{Label: \"2.1\"}) {\n\t\t\t\t\t@components.MenuItem(components.MenuItemProps{Label: \"2.1.1\"})\n\t\t\t\t\t@components.MenuItem(components.MenuItemProps{Label: \"2.1.2\"})\n\t\t\t\t}\n\t\t\t\t@components.MenuItem(components.MenuItemProps{Label: \"2.2\"}) {\n\t\t\t\t\t@components.MenuItem(components.MenuItemProps{Label: \"2.2.1\"})\n\t\t\t\t}\n\t\t\t\t@components.MenuItem(components.MenuItemProps{Label: \"2.3\"})\n\t\t\t}\n\t\t\t@components.MenuItem(components.MenuItemProps{Label: \"Section 3\", Attrs: templ.Attributes{\"class\": \"menu-title\"}}) {\n\t\t\t\t@components.MenuItem(components.MenuItemProps{Label: \"3.1\"})\n\t\t\t}\n\t\t}\n\t\u003c/div\u003e\n}\n\n```",
      "title": "Basic menu"
    },
    {
      "name": "MenuWithSubmenusExample",
      "code": "```go\ntempl MenuWithSubmenusExample() {\n\t\u003cdiv class=\"w-full mx-auto max-w-xs pt-4 min-h-72\"\u003e\n\t\t@components.Menu(components.MenuProps{Class: \"w-52\"}) {\n\t\t\t@components.MenuItem(\n\t\t\t\tcomponents.MenuItemProps{\n\t\t\t\t\tLabel: \"Section 1\",\n\t\t\t\t\tAttrs: templ.Attributes{\"class\": \"menu-title\"},\n\t\t\t\t})\n\t\t\t@components.Submenu(\n\t\t\t\tcomponents.SubmenuProps{\n\t\t\t\t\tTitle: \"Section 2\",\n\t\t\t\t\tAttrs: templ.Attributes{\"open\": \"\"},\n\t\t\t\t},\n\t\t\t) {\n\t\t\t\t@components.MenuItem(components.MenuItemProps{Label: \"2.1\"})\n\t\t\t\t@components.MenuItem(components.MenuItemProps{Label: \"2.2\"})\n\t\t\t}\n\t\t}\n\t\u003c/div\u003e\n}\n\n```",
      "title": "Menu with a submenu"
    },
    {
      "name": "DashboardMenuExample",
      "code": "```go\ntempl DashboardMenuExample() {\n\t@components.Menu(\n\t\tcomponents.MenuProps{Class: \"w-64 bg-base-200 rounded-box\"}) {\n\t\t@components.MenuItem(\n\t\t\tcomponents.MenuItemProps{\n\t\t\t\tLabel: \"Dashboard\",\n\t\t\t\tIcon:  HomeIcon(),\n\t\t\t\tAttrs: templ.Attributes{\"href\": \"#dashboard\"},\n\t\t\t})\n\t\t@components.MenuItem(\n\t\t\tcomponents.MenuItemProps{\n\t\t\t\tLabel: \"Users\",\n\t\t\t\tIcon:  UsersIcon(),\n\t\t\t\tAttrs: templ.Attributes{\"href\": \"#users\"},\n\t\t\t})\n\t\t@components.Submenu(components.SubmenuProps{Title: 
Download .txt
gitextract_6j5602nm/

├── .gitignore
├── LICENSE
├── Makefile
├── cmd/
│   ├── generate/
│   │   └── main.go
│   ├── gsi/
│   │   └── main.go
│   └── server/
│       └── main.go
├── go.mod
├── go.sum
├── input.css
├── internal/
│   ├── assets/
│   │   ├── content/
│   │   │   ├── cli.md
│   │   │   ├── getting_started.md
│   │   │   └── types.md
│   │   ├── embed.go
│   │   ├── generated/
│   │   │   ├── component_code_map.json
│   │   │   ├── component_example_code_map.json
│   │   │   └── components.go
│   │   └── public/
│   │       └── static/
│   │           ├── css/
│   │           │   ├── chroma.css
│   │           │   └── custom.css
│   │           └── js/
│   │               ├── alpine.js
│   │               └── datastar.js
│   ├── components.go
│   ├── echo.go
│   ├── handler/
│   │   ├── components.go
│   │   ├── error.go
│   │   ├── htmx.go
│   │   ├── input_validation.go
│   │   ├── pages.go
│   │   └── render.go
│   ├── markdown/
│   │   └── markdown.go
│   ├── markdown.go
│   ├── model/
│   │   └── generation.go
│   ├── settings.go
│   └── views/
│       ├── components/
│       │   ├── accordion.templ
│       │   ├── active_search.templ
│       │   ├── alert.templ
│       │   ├── anchor.templ
│       │   ├── avatar.templ
│       │   ├── banner.templ
│       │   ├── breadcrumbs.templ
│       │   ├── card.templ
│       │   ├── carousel.templ
│       │   ├── chat.templ
│       │   ├── checkbox.templ
│       │   ├── collapse.templ
│       │   ├── combobox.templ
│       │   ├── countdown.templ
│       │   ├── date_picker.templ
│       │   ├── diff.templ
│       │   ├── drawer.templ
│       │   ├── dropdown.templ
│       │   ├── fab.templ
│       │   ├── features.templ
│       │   ├── file_input.templ
│       │   ├── footer.templ
│       │   ├── hero.templ
│       │   ├── hover_3d_card.templ
│       │   ├── infinite_scroll.templ
│       │   ├── input.templ
│       │   ├── lazy_load.templ
│       │   ├── menu.templ
│       │   ├── modal.templ
│       │   ├── pagination.templ
│       │   ├── pricing.templ
│       │   ├── radio.templ
│       │   ├── range.templ
│       │   ├── rating.templ
│       │   ├── select.templ
│       │   ├── skeleton.templ
│       │   ├── stats.templ
│       │   ├── status.templ
│       │   ├── steps.templ
│       │   ├── swap.templ
│       │   ├── table.templ
│       │   ├── tabs.templ
│       │   ├── testimonial.templ
│       │   ├── text_rotate.templ
│       │   ├── textarea.templ
│       │   ├── time_slot_picker.templ
│       │   ├── timeline.templ
│       │   ├── toast.templ
│       │   ├── toggle.templ
│       │   └── tooltip.templ
│       ├── custom/
│       │   └── toast.templ
│       ├── embed.go
│       ├── examples/
│       │   ├── accordion.templ
│       │   ├── active_search.templ
│       │   ├── alert.templ
│       │   ├── anchor.templ
│       │   ├── avatar.templ
│       │   ├── banner.templ
│       │   ├── breadcrumbs.templ
│       │   ├── card.templ
│       │   ├── carousel.templ
│       │   ├── chat.templ
│       │   ├── checkbox.templ
│       │   ├── collapse.templ
│       │   ├── combobox.templ
│       │   ├── countdown.templ
│       │   ├── date_picker.templ
│       │   ├── diff.templ
│       │   ├── drawer.templ
│       │   ├── dropdown.templ
│       │   ├── fab.templ
│       │   ├── features.templ
│       │   ├── file_input.templ
│       │   ├── footer.templ
│       │   ├── hero.templ
│       │   ├── hover_3d_card.templ
│       │   ├── infinite_scroll.templ
│       │   ├── input.templ
│       │   ├── lazy_load.templ
│       │   ├── menu.templ
│       │   ├── modal.templ
│       │   ├── pagination.templ
│       │   ├── pricing.templ
│       │   ├── radio.templ
│       │   ├── range.templ
│       │   ├── rating.templ
│       │   ├── select.templ
│       │   ├── skeleton.templ
│       │   ├── stats.templ
│       │   ├── status.templ
│       │   ├── steps.templ
│       │   ├── swap.templ
│       │   ├── table.templ
│       │   ├── tabs.templ
│       │   ├── testimonial.templ
│       │   ├── text_rotate.templ
│       │   ├── textarea.templ
│       │   ├── time_slot_picker.templ
│       │   ├── timeline.templ
│       │   ├── toast.templ
│       │   ├── toggle.templ
│       │   └── tooltip.templ
│       ├── pages/
│       │   ├── base.templ
│       │   ├── cli.templ
│       │   ├── client_error.templ
│       │   ├── component.templ
│       │   ├── index.templ
│       │   └── server_error.templ
│       └── scripts/
│           └── copy_button.templ
├── package.json
├── readme.md
└── tailwind.config.js
Download .txt
SYMBOL INDEX (392 symbols across 17 files)

FILE: cmd/generate/main.go
  constant componentCodeMapJSONPath (line 20) | componentCodeMapJSONPath        = "internal/assets/generated/component_c...
  constant componentExampleCodeMapJSONPath (line 21) | componentExampleCodeMapJSONPath = "internal/assets/generated/component_e...
  constant componentsDir (line 22) | componentsDir                   = "internal/views/components/"
  constant componentsHandlerPath (line 23) | componentsHandlerPath           = "internal/handler/components.go"
  constant examplesDir (line 24) | examplesDir                     = "internal/views/examples/"
  constant generatedDir (line 25) | generatedDir                    = "internal/assets/generated"
  constant generatedComponentsPath (line 26) | generatedComponentsPath         = "internal/assets/generated/components.go"
  function main (line 29) | func main() {
  function generateComponentCodeMap (line 35) | func generateComponentCodeMap() {
  function getComponentCode (line 71) | func getComponentCode(path string, info fs.FileInfo, fmap model.Componen...
  function generateComponentExampleCodeMap (line 129) | func generateComponentExampleCodeMap() {
  function addComponentExampleToMap (line 166) | func addComponentExampleToMap(
  function addComponentExampleBackendParts (line 246) | func addComponentExampleBackendParts(
  function generateComponentMap (line 280) | func generateComponentMap() {
  function writeGeneratedFunctions (line 314) | func writeGeneratedFunctions(functionNames []string) {

FILE: cmd/gsi/main.go
  function main (line 19) | func main() {
  constant usageText (line 26) | usageText string = `usage: gsi <command> [<args>...]
  function run (line 37) | func run(stdout, stderr io.Writer, args []string) int {
  function runAddCommand (line 65) | func runAddCommand(stderr io.Writer, name string) int {
  function runRemoveCommand (line 111) | func runRemoveCommand(stdout io.Writer, name string) int {
  function runListCommand (line 125) | func runListCommand(stdout io.Writer) int {

FILE: cmd/server/main.go
  function main (line 13) | func main() {

FILE: internal/assets/public/static/js/alpine.js
  function qt (line 2) | function qt(e) { Cn(e) }
  function Cn (line 2) | function Cn(e) { U.includes(e) || U.push(e), Tn() }
  function Ee (line 2) | function Ee(e) { let t = U.indexOf(e); t !== -1 && t > it && U.splice(t,...
  function Tn (line 2) | function Tn() { !nt && !rt && (rt = !0, queueMicrotask(Rn)) }
  function Rn (line 2) | function Rn() { rt = !1, nt = !0; for (let e = 0; e < U.length; e++)U[e]...
  function Ut (line 2) | function Ut(e) { ot = !1, e(), ot = !0 }
  function Wt (line 2) | function Wt(e) { R = e.reactive, L = e.release, D = t => e.effect(t, { s...
  function at (line 2) | function at(e) { D = e }
  function Gt (line 2) | function Gt(e) { let t = () => { }; return [n => { let i = D(n); return ...
  function ve (line 2) | function ve(e, t) { let r = !0, n, i = D(() => { let o = e(); JSON.strin...
  function Zt (line 2) | function Zt(e) { Xt.push(e) }
  function ee (line 2) | function ee(e, t) { typeof t == "function" ? (e._x_cleanups || (e._x_cle...
  function Ae (line 2) | function Ae(e) { Jt.push(e) }
  function Oe (line 2) | function Oe(e, t, r) { e._x_attributeCleanups || (e._x_attributeCleanups...
  function ct (line 2) | function ct(e, t) { e._x_attributeCleanups && Object.entries(e._x_attrib...
  function Qt (line 2) | function Qt(e) { if (e._x_cleanups) for (; e._x_cleanups.length;)e._x_cl...
  function le (line 2) | function le() { lt.observe(document, { subtree: !0, childList: !0, attri...
  function ft (line 2) | function ft() { Mn(), lt.disconnect(), ut = !1 }
  function Mn (line 2) | function Mn() { let e = lt.takeRecords(); ce.push(() => e.length > 0 && ...
  function _ (line 2) | function _(e) { if (!ut) return e(); ft(); let t = e(); return le(), t }
  function er (line 2) | function er() { dt = !0 }
  function tr (line 2) | function tr() { dt = !1, pt(Se), Se = [] }
  function pt (line 2) | function pt(e) { if (dt) { Se = Se.concat(e); return } let t = new Set, ...
  function Ce (line 2) | function Ce(e) { return F(j(e)) }
  function P (line 2) | function P(e, t, r) { return e._x_dataStack = [t, ...j(r || e)], () => {...
  function j (line 2) | function j(e) { return e._x_dataStack ? e._x_dataStack : typeof ShadowRo...
  function F (line 2) | function F(e) { return new Proxy({ objects: e }, Nn) }
  method ownKeys (line 2) | ownKeys({ objects: e }) { return Array.from(new Set(e.flatMap(t => Objec...
  method has (line 2) | has({ objects: e }, t) { return t == Symbol.unscopables ? !1 : e.some(r ...
  method get (line 2) | get({ objects: e }, t, r) { return t == "toJSON" ? Dn : Reflect.get(e.fi...
  method set (line 2) | set({ objects: e }, t, r, n) { let i = e.find(s => Object.prototype.hasO...
  function Dn (line 2) | function Dn() { return Reflect.ownKeys(this).reduce((t, r) => (t[r] = Re...
  function Te (line 2) | function Te(e) { let t = n => typeof n == "object" && !Array.isArray(n) ...
  function Re (line 2) | function Re(e, t = () => { }) { let r = { initialValue: void 0, _x_inter...
  function Pn (line 2) | function Pn(e, t) { return t.split(".").reduce((r, n) => r[n], e) }
  function mt (line 2) | function mt(e, t, r) { if (typeof t == "string" && (t = t.split(".")), t...
  function y (line 2) | function y(e, t) { rr[e] = t }
  function ue (line 2) | function ue(e, t) { return Object.entries(rr).forEach(([r, n]) => { let ...
  function nr (line 2) | function nr(e, t, r, ...n) { try { return r(...n) } catch (i) { te(i, e,...
  function te (line 2) | function te(e, t, r = void 0) {
  function De (line 8) | function De(e) { let t = Me; Me = !1; let r = e(); return Me = t, r }
  function M (line 8) | function M(e, t, r = {}) { let n; return x(e, t)(i => n = i, r), n }
  function x (line 8) | function x(...e) { return ir(...e) }
  function or (line 8) | function or(e) { ir = e }
  function gt (line 8) | function gt(e, t) { let r = {}; ue(r, e); let n = [r, ...j(e)], i = type...
  function In (line 8) | function In(e, t) { return (r = () => { }, { scope: n = {}, params: i = ...
  function kn (line 8) | function kn(e, t) { if (ht[e]) return ht[e]; let r = Object.getPrototype...
  function Ln (line 8) | function Ln(e, t, r) { let n = kn(t, r); return (i = () => { }, { scope:...
  function Ne (line 8) | function Ne(e, t, r, n, i) { if (Me && typeof t == "function") { let o =...
  function C (line 8) | function C(e = "") { return bt + e }
  function sr (line 8) | function sr(e) { bt = e }
  function d (line 8) | function d(e, t) { return Pe[e] = t, { before(r) { if (!Pe[r]) { console...
  function ar (line 8) | function ar(e) { return Object.keys(Pe).includes(e) }
  function de (line 8) | function de(e, t, r) { if (t = Array.from(t), e._x_virtualDirectives) { ...
  function wt (line 8) | function wt(e) { return Array.from(e).map(ur()).filter(t => !dr(t)) }
  function lr (line 8) | function lr(e) { xt = !0; let t = Symbol(); cr = t, fe.set(t, []); let r...
  function _t (line 8) | function _t(e) { let t = [], r = a => t.push(a), [n, i] = Gt(e); return ...
  function $n (line 8) | function $n(e, t) { let r = () => { }, n = Pe[t.type] || r, [i, o] = _t(...
  function ur (line 8) | function ur(e = () => { }) { return ({ name: t, value: r }) => { let { n...
  function re (line 8) | function re(e) { fr.push(e) }
  function dr (line 8) | function dr({ name: e }) { return pr().test(e) }
  function jn (line 8) | function jn(e, t) { return ({ name: r, value: n }) => { let i = r.match(...
  function Fn (line 8) | function Fn(e, t) { let r = W.indexOf(e.type) === -1 ? yt : e.type, n = ...
  function G (line 8) | function G(e, t, r = {}) { e.dispatchEvent(new CustomEvent(t, { detail: ...
  function T (line 8) | function T(e, t) { if (typeof ShadowRoot == "function" && e instanceof S...
  function E (line 8) | function E(e, ...t) { console.warn(`Alpine Warning: ${e}`, ...t) }
  function _r (line 8) | function _r() { mr && E("Alpine has already been initialized on this pag...
  function gr (line 8) | function gr() { return Et.map(e => e()) }
  function xr (line 8) | function xr() { return Et.concat(hr).map(e => e()) }
  function Le (line 8) | function Le(e) { Et.push(e) }
  function $e (line 8) | function $e(e) { hr.push(e) }
  function J (line 8) | function J(e, t = !1) { return z(e, r => { if ((t ? xr() : gr()).some(i ...
  function z (line 8) | function z(e, t) { if (e) { if (t(e)) return e; if (e._x_teleportBack &&...
  function yr (line 8) | function yr(e) { return gr().some(t => e.matches(t)) }
  function wr (line 8) | function wr(e) { br.push(e) }
  function S (line 8) | function S(e, t = T, r = () => { }) { lr(() => { t(e, (n, i) => { r(n, i...
  function vt (line 8) | function vt(e, t = T) { t(e, r => { ct(r), Qt(r) }) }
  function Bn (line 8) | function Bn() { [["ui", "dialog", ["[x-dialog], [x-popover]"]], ["anchor...
  function ne (line 8) | function ne(e = () => { }) { return queueMicrotask(() => { At || setTime...
  function je (line 8) | function je() { for (At = !1; St.length;)St.shift()() }
  function Er (line 8) | function Er() { At = !0 }
  function pe (line 8) | function pe(e, t) { return Array.isArray(t) ? vr(e, t.join(" ")) : typeo...
  function vr (line 8) | function vr(e, t) { let r = o => o.split(" ").filter(Boolean), n = o => ...
  function zn (line 8) | function zn(e, t) { let r = a => a.split(" ").filter(Boolean), n = Objec...
  function Y (line 8) | function Y(e, t) { return typeof t == "object" && t !== null ? Kn(e, t) ...
  function Kn (line 8) | function Kn(e, t) { let r = {}; return Object.entries(t).forEach(([n, i]...
  function Hn (line 8) | function Hn(e, t) { let r = e.getAttribute("style", t); return e.setAttr...
  function Vn (line 8) | function Vn(e) { return e.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCas...
  function me (line 8) | function me(e, t = () => { }) { let r = !1; return function () { r ? t.a...
  function qn (line 8) | function qn(e, t, r) { Sr(e, pe, ""), { enter: i => { e._x_transition.en...
  function Un (line 8) | function Un(e, t, r) { Sr(e, Y); let n = !t.includes("in") && !t.include...
  function Sr (line 8) | function Sr(e, t, r = {}) { e._x_transition || (e._x_transition = { ente...
  function Ar (line 8) | function Ar(e) { let t = e.parentNode; if (t) return t._x_hidePromise ? ...
  function Fe (line 8) | function Fe(e, t, { during: r, start: n, end: i } = {}, o = () => { }, s...
  function Wn (line 8) | function Wn(e, t) { let r, n, i, o = me(() => { _(() => { r = !0, n || t...
  function _e (line 8) | function _e(e, t, r) { if (e.indexOf(t) === -1) return r; let n = e[e.in...
  function A (line 8) | function A(e, t = () => { }) { return (...r) => I ? t(...r) : e(...r) }
  function Or (line 8) | function Or(e) { return (...t) => I && e(...t) }
  function K (line 8) | function K(e) { Cr.push(e) }
  function Tr (line 8) | function Tr(e, t) { Cr.forEach(r => r(e, t)), I = !0, Mr(() => { S(t, (r...
  function Rr (line 8) | function Rr(e, t) { t._x_dataStack || (t._x_dataStack = e._x_dataStack),...
  function Gn (line 8) | function Gn(e) { let t = !1; S(e, (n, i) => { T(n, (o, s) => { if (t && ...
  function Mr (line 8) | function Mr(e) { let t = D; at((r, n) => { let i = t(r); return L(i), ()...
  function he (line 8) | function he(e, t, r, n = []) { switch (e._x_bindings || (e._x_bindings =...
  function Jn (line 8) | function Jn(e, t) { if (e.type === "radio") e.attributes.value === void ...
  function Yn (line 8) | function Yn(e, t) { e._x_undoAddedClasses && e._x_undoAddedClasses(), e....
  function Xn (line 8) | function Xn(e, t) { e._x_undoAddedStyles && e._x_undoAddedStyles(), e._x...
  function Zn (line 8) | function Zn(e, t, r) { Dr(e, t, r), ei(e, t, r) }
  function Dr (line 8) | function Dr(e, t, r) { [null, void 0, !1].includes(r) && ni(t) ? e.remov...
  function Qn (line 8) | function Qn(e, t, r) { e.getAttribute(t) != r && e.setAttribute(t, r) }
  function ei (line 8) | function ei(e, t, r) { e[t] !== r && (e[t] = r) }
  function ti (line 8) | function ti(e, t) { let r = [].concat(t).map(n => n + ""); Array.from(e....
  function ri (line 8) | function ri(e) { return e.toLowerCase().replace(/-(\w)/g, (t, r) => r.to...
  function Nr (line 8) | function Nr(e, t) { return e == t }
  function ge (line 8) | function ge(e) { return [1, "1", "true", "on", "yes", !0].includes(e) ? ...
  function Pr (line 8) | function Pr(e) { return ["disabled", "checked", "required", "readonly", ...
  function ni (line 8) | function ni(e) { return !["aria-pressed", "aria-checked", "aria-expanded...
  function Ir (line 8) | function Ir(e, t, r) { return e._x_bindings && e._x_bindings[t] !== void...
  function kr (line 8) | function kr(e, t, r, n = !0) { if (e._x_bindings && e._x_bindings[t] !==...
  function Lr (line 8) | function Lr(e, t, r) { let n = e.getAttribute(t); return n === null ? ty...
  function ze (line 8) | function ze(e, t) { var r; return function () { var n = this, i = argume...
  function Ke (line 8) | function Ke(e, t) { let r; return function () { let n = this, i = argume...
  function He (line 8) | function He({ get: e, set: t }, { get: r, set: n }) { let i = !0, o, s, ...
  function Ot (line 8) | function Ot(e) { return typeof e == "object" ? JSON.parse(JSON.stringify...
  function $r (line 8) | function $r(e) { (Array.isArray(e) ? e : [e]).forEach(r => r(B)) }
  function Fr (line 8) | function Fr(e, t) { if (jr || (X = R(X), jr = !0), t === void 0) return ...
  function Br (line 8) | function Br() { return X }
  function Kr (line 8) | function Kr(e, t) { let r = typeof t != "function" ? () => t : t; return...
  function Hr (line 8) | function Hr(e) { return Object.entries(zr).forEach(([t, r]) => { Object....
  function Ct (line 8) | function Ct(e, t, r) { let n = []; for (; n.length;)n.pop()(); let i = O...
  function qr (line 8) | function qr(e, t) { Vr[e] = t }
  function Ur (line 8) | function Ur(e, t) { return Object.entries(Vr).forEach(([r, n]) => { Obje...
  method reactive (line 8) | get reactive() { return R }
  method release (line 8) | get release() { return L }
  method effect (line 8) | get effect() { return D }
  method raw (line 8) | get raw() { return st }
  function Tt (line 8) | function Tt(e, t) { let r = Object.create(null), n = e.split(","); for (...
  function fi (line 8) | function fi(e) { return e && e._isEffect === !0 }
  function en (line 8) | function en(e, t = Wr) { fi(e) && (e = e.raw); let r = pi(e, t); return ...
  function tn (line 8) | function tn(e) { e.active && (rn(e), e.options.onStop && e.options.onSto...
  function pi (line 8) | function pi(e, t) { let r = function () { if (!r.active) return e(); if ...
  function rn (line 8) | function rn(e) { let { deps: t } = e; if (t.length) { for (let r = 0; r ...
  function mi (line 8) | function mi() { kt.push(oe), oe = !1 }
  function _i (line 8) | function _i() { kt.push(oe), oe = !0 }
  function nn (line 8) | function nn() { let e = kt.pop(); oe = e === void 0 ? !0 : e }
  function N (line 8) | function N(e, t, r) { if (!oe || k === void 0) return; let n = Dt.get(e)...
  function q (line 8) | function q(e, t, r, n, i, o) { let s = Dt.get(e); if (!s) return; let a ...
  function yi (line 8) | function yi() { let e = {}; return ["includes", "indexOf", "lastIndexOf"...
  function sn (line 8) | function sn(e = !1, t = !1) { return function (n, i, o) { if (i === "__v...
  function wi (line 8) | function wi(e = !1) { return function (r, n, i, o) { let s = r[n]; if (!...
  function Ei (line 8) | function Ei(e, t) { let r = xe(e, t), n = e[t], i = Reflect.deleteProper...
  function vi (line 8) | function vi(e, t) { let r = Reflect.has(e, t); return (!Ve(t) || !on.has...
  function Si (line 8) | function Si(e) { return N(e, "iterate", H(e) ? "length" : Z), Reflect.ow...
  method set (line 8) | set(e, t) { return console.warn(`Set operation on key "${String(t)}" fai...
  method deleteProperty (line 8) | deleteProperty(e, t) { return console.warn(`Delete operation on key "${S...
  function We (line 8) | function We(e, t, r = !1, n = !1) { e = e.__v_raw; let i = h(e), o = h(t...
  function Ge (line 8) | function Ge(e, t = !1) { let r = this.__v_raw, n = h(r), i = h(e); retur...
  function Je (line 8) | function Je(e, t = !1) { return e = e.__v_raw, !t && N(h(e), "iterate", ...
  function Yr (line 8) | function Yr(e) { e = h(e); let t = h(this); return Ze(t).has.call(t, e) ...
  function Xr (line 8) | function Xr(e, t) { t = h(t); let r = h(this), { has: n, get: i } = Ze(r...
  function Zr (line 8) | function Zr(e) { let t = h(this), { has: r, get: n } = Ze(t), i = r.call...
  function Qr (line 8) | function Qr() { let e = h(this), t = e.size !== 0, r = ie(e) ? new Map(e...
  function Ye (line 8) | function Ye(e, t) { return function (n, i) { let o = this, s = o.__v_raw...
  function Xe (line 8) | function Xe(e, t, r) { return function (...n) { let i = this.__v_raw, o ...
  function V (line 8) | function V(e) { return function (...t) { { let r = t[0] ? `on key "${t[0...
  function Ci (line 8) | function Ci() { let e = { get(o) { return We(this, o) }, get size() { re...
  function an (line 8) | function an(e, t) { let r = t ? e ? Ni : Mi : e ? Ri : Ti; return (n, i,...
  function cn (line 8) | function cn(e, t, r) { let n = h(r); if (n !== r && t.call(e, n)) { let ...
  function Li (line 8) | function Li(e) { switch (e) { case "Object": case "Array": return 1; cas...
  function $i (line 8) | function $i(e) { return e.__v_skip || !Object.isExtensible(e) ? 0 : Li(R...
  function Qe (line 8) | function Qe(e) { return e && e.__v_isReadonly ? e : dn(e, !1, Ai, Di, ln) }
  function fn (line 8) | function fn(e) { return dn(e, !0, Oi, Pi, un) }
  function dn (line 8) | function dn(e, t, r, n, i) { if (!ye(e)) return console.warn(`value cann...
  function h (line 8) | function h(e) { return e && h(e.__v_raw) || e }
  function It (line 8) | function It(e) { return Boolean(e && e.__v_isRef === !0) }
  function ji (line 8) | function ji(e) { let t = []; return z(e, r => { r._x_refs && t.push(r._x...
  function Bt (line 8) | function Bt(e) { return Ft[e] || (Ft[e] = 0), ++Ft[e] }
  function pn (line 8) | function pn(e, t) { return z(e, r => { if (r._x_ids && r._x_ids[t]) retu...
  function mn (line 8) | function mn(e, t) { e._x_ids || (e._x_ids = {}), e._x_ids[t] || (e._x_id...
  function Fi (line 8) | function Fi(e, t, r, n) { if (e._x_id || (e._x_id = {}), e._x_id[t]) ret...
  function _n (line 8) | function _n(e, t, r) { y(t, n => E(`You can't use [$${t}] without first ...
  method get (line 8) | get() { return u() }
  method set (line 8) | set(w) { p(w) }
  method get (line 8) | get() { return s() }
  method set (line 8) | set(w) { c(w) }
  function hn (line 8) | function hn(e) { let t = A(() => document.querySelector(e), () => Bi)();...
  function se (line 8) | function se(e, t, r, n) { let i = e, o = c => n(c), s = {}, a = (c, l) =...
  function zi (line 8) | function zi(e) { return e.replace(/-/g, ".") }
  function Ki (line 8) | function Ki(e) { return e.toLowerCase().replace(/-(\w)/g, (t, r) => r.to...
  function et (line 8) | function et(e) { return !Array.isArray(e) && !isNaN(e) }
  function Hi (line 8) | function Hi(e) { return [" ", "_"].includes(e) ? e : e.replace(/([a-z])(...
  function Vi (line 8) | function Vi(e) { return ["keydown", "keyup"].includes(e) }
  function yn (line 8) | function yn(e) { return ["contextmenu", "click", "mouse"].some(t => e.in...
  function qi (line 8) | function qi(e, t) { let r = t.filter(o => !["window", "document", "preve...
  function xn (line 8) | function xn(e) { if (!e) return []; e = Hi(e); let t = { ctrl: "control"...
  method get (line 8) | get() { return c() }
  method set (line 8) | set(m) { l(m) }
  function zt (line 8) | function zt(e, t, r, n) { return _(() => { if (r instanceof CustomEvent ...
  function Kt (line 8) | function Kt(e) { let t = e ? parseFloat(e) : null; return Wi(t) ? t : e }
  function Ui (line 8) | function Ui(e, t) { return e == t }
  function Wi (line 8) | function Wi(e) { return !Array.isArray(e) && !isNaN(e) }
  function bn (line 8) | function bn(e) { return e !== null && typeof e == "object" && typeof e.g...
  function Gi (line 8) | function Gi(e, t) { e._x_keyExpression = t }
  function Ji (line 8) | function Ji(e) { return I ? Be ? !0 : e.hasAttribute("data-has-alpine-st...
  function Yi (line 8) | function Yi(e, t, r, n) { let i = s => typeof s == "object" && !Array.is...
  function Xi (line 8) | function Xi(e) { let t = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/, r = /^\s*\(|\...
  function En (line 8) | function En(e, t, r, n) { let i = {}; return /^\[.*\]$/.test(e.item) && ...
  function Zi (line 8) | function Zi(e) { return !Array.isArray(e) && !isNaN(e) }
  function vn (line 8) | function vn() { }
  function tt (line 8) | function tt(e, t, r) { d(t, n => E(`You can't use [x-${t}] without first...

FILE: internal/assets/public/static/js/datastar.js
  method constructor (line 2) | constructor(e=L){this.#t=e}
  method with (line 2) | with(e){if(typeof e=="string")for(let n of e.split(""))this.with(n.charC...
  method reset (line 2) | reset(){return this.#e=0,this}
  method value (line 2) | get value(){return this.#t+Math.abs(this.#e).toString(36)}
  function tt (line 2) | function tt(t){if(t.id)return t.id;let e=new ie,n=t;for(;n.parentNode;){...
  function nt (line 2) | function nt(t,e){let n=new MutationObserver(r=>{for(let i of r)for(let s...
  function De (line 2) | function De(t,e,n={}){let r=new Error;e=e[0].toUpperCase()+e.slice(1),r....
  function P (line 4) | function P(t,e,n={}){return De("internal",e,Object.assign({from:t},n))}
  function V (line 4) | function V(t,e,n={}){let r={plugin:{name:e.plugin.name,type:p[e.plugin.t...
  function h (line 4) | function h(t,e,n={}){let r={plugin:{name:e.plugin.name,type:p[e.plugin.t...
  function Oe (line 4) | function Oe(){ve++}
  function Ve (line 4) | function Ve(){if(ve>1){ve--;return}let t,e=!1;for(;oe!==void 0;){let n=o...
  function rt (line 4) | function rt(t){if(v===void 0)return;let e=t._node;if(e===void 0||e._targ...
  function R (line 4) | function R(t){this._value=t,this._version=0,this._node=void 0,this._targ...
  method get (line 4) | get(){let t=rt(this);return t!==void 0&&(t._version=this._version),this....
  method set (line 4) | set(t){if(t!==this._value){if(Le>100)throw P(G,"SignalCycleDetected");th...
  function it (line 4) | function it(t){for(let e=t._sources;e!==void 0;e=e._nextSource)if(e._sou...
  function ot (line 4) | function ot(t){for(let e=t._sources;e!==void 0;e=e._nextSource){let n=e....
  function st (line 4) | function st(t){let e=t._sources,n;for(;e!==void 0;){let r=e._prevSource;...
  function K (line 4) | function K(t){R.call(this,void 0),this._fn=t,this._sources=void 0,this._...
  method get (line 4) | get(){if(this._flags&F)throw P(G,"SignalCycleDetected");let t=rt(this);i...
  function at (line 4) | function at(t){return new K(t)}
  function lt (line 4) | function lt(t){let e=t._cleanup;if(t._cleanup=void 0,typeof e=="function...
  function Fe (line 4) | function Fe(t){for(let e=t._sources;e!==void 0;e=e._nextSource)e._source...
  function Mn (line 4) | function Mn(t){if(v!==this)throw P(G,"EndEffectError");st(this),v=t,this...
  function ae (line 4) | function ae(t){this._fn=t,this._cleanup=void 0,this._sources=void 0,this...
  function Se (line 4) | function Se(t){let e=new ae(t);try{e._callback()}catch(n){throw e._dispo...
  function ct (line 4) | function ct(t,e=!1){let n={};for(let r in t)if(Object.hasOwn(t,r)){if(e&...
  function ft (line 4) | function ft(t,e,n=!1){for(let r in e)if(Object.hasOwn(e,r)){if(r.match(/...
  function dt (line 4) | function dt(t,e){for(let n in t)if(Object.hasOwn(t,n)){let r=t[n];r inst...
  function Cn (line 4) | function Cn(t,...e){let n={};for(let r of e){let i=r.split("."),s=t,o=n;...
  method exists (line 4) | exists(e){return!!this.signal(e)}
  method signal (line 4) | signal(e){let n=e.split("."),r=this.#e;for(let o=0;o<n.length-1;o++){let...
  method setSignal (line 4) | setSignal(e,n){let r=e.split("."),i=this.#e;for(let o=0;o<r.length-1;o++...
  method setComputed (line 4) | setComputed(e,n){let r=at(()=>n());this.setSignal(e,r)}
  method value (line 4) | value(e){return this.signal(e)?.value}
  method setValue (line 4) | setValue(e,n){let r=this.upsertIfMissing(e,n);r.value=n}
  method upsertIfMissing (line 4) | upsertIfMissing(e,n){let r=e.split("."),i=this.#e;for(let l=0;l<r.length...
  method remove (line 4) | remove(...e){for(let n of e){let r=n.split("."),i=this.#e;for(let o=0;o<...
  method merge (line 4) | merge(e,n=!1){ft(this.#e,e,n)}
  method subset (line 4) | subset(...e){return Cn(this.values(),...e)}
  method walk (line 4) | walk(e){dt(this.#e,e)}
  method paths (line 4) | paths(){let e=new Array;return this.walk(n=>e.push(n)),e}
  method values (line 4) | values(e=!1){return ct(this.#e,e)}
  method JSON (line 4) | JSON(e=!0,n=!1){let r=this.values(n);return e?JSON.stringify(r,null,2):J...
  method toString (line 4) | toString(){return this.JSON()}
  method signals (line 4) | get signals(){return this.#e}
  method version (line 4) | get version(){return Ge}
  method load (line 4) | load(...e){for(let n of e){let r=this,i={get signals(){return r.#e},effe...
  method apply (line 4) | apply(e){this.#o(e,n=>{this.#i(n);for(let r of Object.keys(n.dataset)){l...
  method #a (line 4) | #a(e,...n){let r=e.value.split(/;|\n/).map(f=>f.trim()).filter(f=>f!==""...
  method #o (line 7) | #o(e,n){if(!e||!(e instanceof HTMLElement||e instanceof SVGElement))retu...
  method #i (line 7) | #i(e){let n=this.#n.get(e);if(n){for(let r of n.fns)r();this.#n.delete(e)}}
  function In (line 7) | async function In(t,e){let n=t.getReader(),r;for(;!(r=await n.read()).do...
  function kn (line 7) | function kn(t){let e,n,r,i=!1;return function(o){e===void 0?(e=o,n=0,r=-...
  function Dn (line 7) | function Dn(t,e,n){let r=mt(),i=new TextDecoder;return function(o,a){if(...
  function Ln (line 8) | function Ln(t,e){let n=new Uint8Array(t.length+e.length);return n.set(t)...
  function mt (line 8) | function mt(){return{data:"",event:"",id:"",retry:void 0}}
  function ht (line 8) | function ht(t,e,{signal:n,headers:r,onopen:i,onmessage:s,onclose:o,onerr...
  function H (line 8) | function H(t,e){document.addEventListener(Q,n=>{if(n.detail.type!==t)ret...
  function Re (line 8) | function Re(t,e){document.dispatchEvent(new CustomEvent(Q,{detail:{type:...
  function Nt (line 11) | function Nt(t,e,n={}){t instanceof Document&&(t=t.documentElement);let r...
  function Mt (line 11) | function Mt(t,e,n){if(n.head.block){let r=t.querySelector("head"),i=e.qu...
  function Ne (line 11) | function Ne(t,e,n){if(!(n.ignoreActive&&t===document.activeElement))if(e...
  function Ct (line 11) | function Ct(t,e,n){let r=t.firstChild,i=e.firstChild,s;for(;r;){if(s=r,r...
  function Vn (line 11) | function Vn(t,e){let n=t.nodeType;if(n===1){for(let r of t.attributes)e....
  function xe (line 11) | function xe(t,e,n){let r=t.getAttribute(n),i=e.getAttribute(n);r!==i&&(r...
  function It (line 11) | function It(t,e,n){let r=[],i=[],s=[],o=[],a=n.head.style,l=new Map;for(...
  function B (line 11) | function B(){}
  function Fn (line 11) | function Fn(t,e,n){return{target:t,newContent:e,config:n,morphStyle:n.mo...
  function kt (line 11) | function kt(t,e,n){return!t||!e?!1:t.nodeType===e.nodeType&&t.tagName===...
  function Me (line 11) | function Me(t,e){return!t||!e?!1:t.nodeType===e.nodeType&&t.tagName===e....
  function Rt (line 11) | function Rt(t,e,n){for(;t!==e;){let r=t;if(t=t?.nextSibling,!r)throw P(t...
  function Hn (line 11) | function Hn(t,e,n,r,i){let s=ue(i,n,e),o=null;if(s>0){o=r;let a=0;for(;o...
  function qn (line 11) | function qn(t,e,n,r){let i=n,s=e.nextSibling,o=0;for(;i&&s;){if(ue(r,i,t...
  function Wn (line 11) | function Wn(t){let e=t.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,""...
  function $n (line 11) | function $n(t){if(t==null)return document.createElement("div");if(Pe.has...
  function Un (line 11) | function Un(t,e,n){let r=[],i=[];for(;t;)r.push(t),t=t.previousSibling;f...
  function jn (line 11) | function jn(t,e,n){let r=t.firstChild,i=r,s=0;for(;r;){let o=Bn(r,e,n);o...
  function Bn (line 11) | function Bn(t,e,n){return Me(t,e)?.5+ue(n,t,e):0}
  function Dt (line 11) | function Dt(t,e){z(e,t),e.callbacks.beforeNodeRemoved(t)!==!1&&(t.remove...
  function Gn (line 11) | function Gn(t,e){return!t.deadIds.has(e)}
  function Kn (line 11) | function Kn(t,e,n){return t.idMap.get(n)?.has(e)||!1}
  function z (line 11) | function z(t,e){let n=t.idMap.get(e);if(n)for(let r of n)t.deadIds.add(r)}
  function ue (line 11) | function ue(t,e,n){let r=t.idMap.get(e);if(!r)return 0;let i=0;for(let s...
  function Pt (line 11) | function Pt(t,e){let n=t.parentElement,r=t.querySelectorAll("[id]");for(...
  function Jn (line 11) | function Jn(t,e){let n=new Map;return Pt(t,n),Pt(e,n),n}
  function Lt (line 11) | function Lt(t,e,n,r,i){for(let s of i){s.classList.add(J);let o=s.outerH...
  method onGlobalInit (line 12) | onGlobalInit(){let t=!1;for(let e of document.head.childNodes)e instance...
  function ce (line 12) | function ce(t){if(!t||t.size<=0)return 0;for(let e of t){if(e.endsWith("...
  function ne (line 12) | function ne(t,e,n=!1){return t?t.has(e.toLowerCase()):n}
  function yn (line 12) | function yn(t,e,n=!1){return function(...i){n?t(...i):setTimeout(()=>{t(...
  function vn (line 12) | function vn(t,e,n=!1,r=!0){let i=-1,s=()=>i&&clearTimeout(i);return func...
  function bn (line 12) | function bn(t,e,n=!0,r=!1){let i=!1;return function(...o){i||(n&&t(...o)...

FILE: internal/components.go
  function init (line 14) | func init() {
  function getComponentCodeMap (line 19) | func getComponentCodeMap() {
  function getComponentExampleCodeMap (line 36) | func getComponentExampleCodeMap() {
  function SnakeCaseToCapitalized (line 55) | func SnakeCaseToCapitalized(s string) string {

FILE: internal/echo.go
  function GracefulShutdown (line 15) | func GracefulShutdown(e *echo.Echo, port string) {
  function GetRateLimiterConfig (line 33) | func GetRateLimiterConfig() middleware.RateLimiterConfig {

FILE: internal/handler/components.go
  function GetComponentAnchors (line 24) | func GetComponentAnchors(c echo.Context) error {
  function GetComponentPage (line 34) | func GetComponentPage(c echo.Context) error {
  function GetComponentSearch (line 82) | func GetComponentSearch(c echo.Context) error {
  function GetActiveSearchExample (line 111) | func GetActiveSearchExample(c echo.Context) error {
  function GetInfiniteScrollExample (line 133) | func GetInfiniteScrollExample(c echo.Context) error {
  function GetInfiniteScrollExampleRows (line 153) | func GetInfiniteScrollExampleRows(c echo.Context) error {
  function GetLazyLoadExample (line 188) | func GetLazyLoadExample(c echo.Context) error {
  function GetCascadingSelectExample (line 214) | func GetCascadingSelectExample(c echo.Context) error {
  constant ItemsPerPage (line 224) | ItemsPerPage = 10
  constant PagesPerSide (line 225) | PagesPerSide = 3
  function GetPaginationExamplePage (line 228) | func GetPaginationExamplePage(c echo.Context) error {
  function getPaginationLowAndHigh (line 262) | func getPaginationLowAndHigh(page, maxPages, pagePerSide int) (int, int) {
  function PostCombobox (line 287) | func PostCombobox(c echo.Context) error {
  function PostComboboxSubmit (line 294) | func PostComboboxSubmit(c echo.Context) error {
  function DeleteModalExample (line 311) | func DeleteModalExample(c echo.Context) error {
  function GetDatePicker (line 320) | func GetDatePicker(c echo.Context) error {
  function PostDatePickerSelectDay (line 358) | func PostDatePickerSelectDay(c echo.Context) error {
  function GetDatePickerMonthPicker (line 371) | func GetDatePickerMonthPicker(c echo.Context) error {
  function GetDatePickerYearPicker (line 386) | func GetDatePickerYearPicker(c echo.Context) error {
  function GetTimeSlotPicker (line 404) | func GetTimeSlotPicker(c echo.Context) error {
  function getTimeSlots (line 421) | func getTimeSlots(date time.Time) []components.TimeSlot {
  function PostTimeSlotPickerReserve (line 434) | func PostTimeSlotPickerReserve(c echo.Context) error {

FILE: internal/handler/error.go
  function ErrorHandler (line 11) | func ErrorHandler(err error, c echo.Context) {
  type ErrorToast (line 28) | type ErrorToast struct
    method Error (line 33) | func (te ErrorToast) Error() string {
  function newErrorToast (line 37) | func newErrorToast(status int, messages ...string) ErrorToast {
  function NotFound (line 44) | func NotFound(c echo.Context) error {

FILE: internal/handler/htmx.go
  function hxRetarget (line 5) | func hxRetarget(c echo.Context, target string) {
  function hxReswap (line 9) | func hxReswap(c echo.Context, swap string) {
  function isHXRequest (line 13) | func isHXRequest(c echo.Context) bool {

FILE: internal/handler/input_validation.go
  function PostValidateString (line 64) | func PostValidateString(c echo.Context) error {

FILE: internal/handler/pages.go
  constant contentTypesMarkdownPath (line 19) | contentTypesMarkdownPath   = "content/types.md"
  constant gettingStartedMarkdownPath (line 20) | gettingStartedMarkdownPath = "content/getting_started.md"
  constant cliMarkdownPath (line 21) | cliMarkdownPath            = "content/cli.md"
  function getGettingStartedHTML (line 24) | func getGettingStartedHTML() {
  function getTypesHTML (line 37) | func getTypesHTML() {
  function getCLIHTML (line 50) | func getCLIHTML() {
  function GetIndexPage (line 62) | func GetIndexPage(c echo.Context) error {
  function GetAboutPage (line 69) | func GetAboutPage(c echo.Context) error {
  function GetGettingStartedPage (line 76) | func GetGettingStartedPage(c echo.Context) error {
  function GetTypesPage (line 85) | func GetTypesPage(c echo.Context) error {
  function GetCLIPage (line 94) | func GetCLIPage(c echo.Context) error {
  function GetPrivacyPolicyPage (line 103) | func GetPrivacyPolicyPage(c echo.Context) error {
  function GetTermsOfServicePage (line 114) | func GetTermsOfServicePage(c echo.Context) error {

FILE: internal/handler/render.go
  function render (line 12) | func render(c echo.Context, status int, com templ.Component) error {
  function renderErrorConfirm (line 23) | func renderErrorConfirm(c echo.Context, status int, errs []string) error {
  function renderInfoFade (line 29) | func renderInfoFade(c echo.Context, status int, messages []string) error {
  function getHTMLFromComponent (line 35) | func getHTMLFromComponent(com templ.Component) string {

FILE: internal/markdown.go
  function GetHTMLFromMarkdown (line 16) | func GetHTMLFromMarkdown(markdown []byte) string {
  function replaceCodeParts (line 26) | func replaceCodeParts(mdFile []byte) (string, error) {

FILE: internal/markdown/markdown.go
  function GetHTMLFromMarkdown (line 16) | func GetHTMLFromMarkdown(markdown []byte) string {
  function replaceCodeParts (line 26) | func replaceCodeParts(mdFile []byte) (string, error) {
  function CodeSliceToMarkdown (line 69) | func CodeSliceToMarkdown(s []string) string {

FILE: internal/model/generation.go
  type ComponentCode (line 3) | type ComponentCode struct
  type ComponentCodeMap (line 14) | type ComponentCodeMap
  type ComponentExampleCodeMap (line 16) | type ComponentExampleCodeMap

FILE: internal/settings.go
  function NewSettings (line 14) | func NewSettings() *AppSettings {
  function getEnvOrDefault (line 27) | func getEnvOrDefault(key, defaultValue string) string {
  type AppSettings (line 35) | type AppSettings struct
  function ReadDotenv (line 42) | func ReadDotenv() {
Condensed preview — 144 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (661K chars).
[
  {
    "path": ".gitignore",
    "chars": 107,
    "preview": ".vscode/\n.env\n*_templ.go\n*_templ.txt\nbin/\nnode_modules/\ninternal/assets/public/static/css/tw.css\n.DS_Store\n"
  },
  {
    "path": "LICENSE",
    "chars": 1073,
    "preview": "MIT License\n\nCopyright (c) 2024 Tomi Haapalainen\n\nPermission is hereby granted, free of charge, to any person obtaining "
  },
  {
    "path": "Makefile",
    "chars": 811,
    "preview": ".DEFAULT_GOAL := dev\n\nGOOS := \"linux\"\nGOARCH := \"amd64\"\n\ndeploy:\n\tnpx @tailwindcss/cli -i input.css -o ./internal/assets"
  },
  {
    "path": "cmd/generate/main.go",
    "chars": 8002,
    "preview": "package main\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"go/format\"\n\t\"io/fs\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"s"
  },
  {
    "path": "cmd/gsi/main.go",
    "chars": 4226,
    "preview": "package main\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/"
  },
  {
    "path": "cmd/server/main.go",
    "chars": 2505,
    "preview": "package main\n\nimport (\n\t\"github.com/haatos/goshipit/internal\"\n\t\"github.com/haatos/goshipit/internal/assets\"\n\t\"github.com"
  },
  {
    "path": "go.mod",
    "chars": 875,
    "preview": "module github.com/haatos/goshipit\n\ngo 1.24\n\nrequire (\n\tgithub.com/PuerkitoBio/goquery v1.10.1\n\tgithub.com/a-h/templ v0.3"
  },
  {
    "path": "go.sum",
    "chars": 11168,
    "preview": "github.com/PuerkitoBio/goquery v1.10.1 h1:Y8JGYUkXWTGRB6Ars3+j3kN0xg1YqqlwvdTV8WTFQcU=\ngithub.com/PuerkitoBio/goquery v1"
  },
  {
    "path": "input.css",
    "chars": 175,
    "preview": "@import \"tailwindcss\";\n@plugin \"@tailwindcss/typography\";\n@source \"./internal/views/**/*.templ\";\n@plugin \"daisyui\" {\n  t"
  },
  {
    "path": "internal/assets/content/cli.md",
    "chars": 490,
    "preview": "# CLI\n\n## Installation\n\n```\ngo install github.com/haatos/cmd/gsi\n```\n\nThen run `gsi` in your terminal to see a list of c"
  },
  {
    "path": "internal/assets/content/getting_started.md",
    "chars": 6699,
    "preview": "# Getting started\n\nTo get started with goship.it in a new project using _Echo_ router:\n\n- Create a new folder for your p"
  },
  {
    "path": "internal/assets/content/types.md",
    "chars": 6468,
    "preview": "# Types\n\n## Introduction\n\nMost components use a struct as the input argument. This provides a convenient way to pass def"
  },
  {
    "path": "internal/assets/embed.go",
    "chars": 168,
    "preview": "package assets\n\nimport \"embed\"\n\n//go:embed public/*\nvar PublicFS embed.FS\n\n//go:embed content/*\nvar ContentFS embed.FS\n\n"
  },
  {
    "path": "internal/assets/generated/component_code_map.json",
    "chars": 83206,
    "preview": "{\n  \"actions\": [\n    {\n      \"name\": \"dropdown\",\n      \"code\": \"```go\\ntype DropdownProps struct {\\n\\tLabel     string\\n"
  },
  {
    "path": "internal/assets/generated/component_example_code_map.json",
    "chars": 123882,
    "preview": "{\n  \"accordion\": [\n    {\n      \"name\": \"AccordionWithCheckbox\",\n      \"code\": \"```go\\n\\ntempl AccordionWithCheckbox() {\\"
  },
  {
    "path": "internal/assets/generated/components.go",
    "chars": 5789,
    "preview": "package generated\n\nimport (\n\t\"github.com/a-h/templ\"\n\t\"github.com/haatos/goshipit/internal/views/examples\"\n)\n\nvar Example"
  },
  {
    "path": "internal/assets/public/static/css/chroma.css",
    "chars": 3706,
    "preview": ".bg {\n  color: #b0c4de;\n  background-color: #282c34;\n}\n\n.chroma {\n  color: #b0c4de;\n  background-color: #111318;\n}\n\n.chr"
  },
  {
    "path": "internal/assets/public/static/css/custom.css",
    "chars": 761,
    "preview": ".font-saira-black {\n  font-family: \"Saira\", sans-serif;\n  font-weight: 900;\n  font-style: normal;\n}\n\nbody,\nhtml {\n  marg"
  },
  {
    "path": "internal/assets/public/static/js/alpine.js",
    "chars": 53177,
    "preview": "(() => {\n    var rt = !1, nt = !1, U = [], it = -1; function qt(e) { Cn(e) } function Cn(e) { U.includes(e) || U.push(e)"
  },
  {
    "path": "internal/assets/public/static/js/datastar.js",
    "chars": 36404,
    "preview": "// Datastar v1.0.0-beta.2\nvar je=/🖕JS_DS🚀/.source,pe=je.slice(0,5),ke=je.slice(4),L=\"datastar\";var Be=\"Datastar-Request\""
  },
  {
    "path": "internal/components.go",
    "chars": 1464,
    "preview": "package internal\n\nimport (\n\t\"encoding/json\"\n\t\"log\"\n\n\t\"github.com/haatos/goshipit/internal/assets\"\n\t\"github.com/haatos/go"
  },
  {
    "path": "internal/echo.go",
    "chars": 1304,
    "preview": "package internal\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/signal\"\n\t\"time\"\n\n\t\"github.com/labstack/echo/v4\"\n\t\"github.co"
  },
  {
    "path": "internal/handler/components.go",
    "chars": 11586,
    "preview": "package handler\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"math\"\n\t\"net/http\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/a-h/temp"
  },
  {
    "path": "internal/handler/error.go",
    "chars": 1007,
    "preview": "package handler\n\nimport (\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/haatos/goshipit/internal/views/pages\"\n\t\"github.com/labsta"
  },
  {
    "path": "internal/handler/htmx.go",
    "chars": 358,
    "preview": "package handler\n\nimport \"github.com/labstack/echo/v4\"\n\nfunc hxRetarget(c echo.Context, target string) {\n\tc.Response().Wr"
  },
  {
    "path": "internal/handler/input_validation.go",
    "chars": 1747,
    "preview": "package handler\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"regexp\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/haatos/goshipit/internal/view"
  },
  {
    "path": "internal/handler/pages.go",
    "chars": 2862,
    "preview": "package handler\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/haatos/goshipit/internal\"\n\t\"github.com/haatos/goshipit/intern"
  },
  {
    "path": "internal/handler/render.go",
    "chars": 1031,
    "preview": "package handler\n\nimport (\n\t\"context\"\n\n\t\"github.com/a-h/templ\"\n\t\"github.com/haatos/goshipit/internal/views/custom\"\n\t\"gith"
  },
  {
    "path": "internal/markdown/markdown.go",
    "chars": 1661,
    "preview": "package markdown\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"log\"\n\t\"strings\"\n\n\t\"github.com/PuerkitoBio/goquery\"\n\tchromaHTML \"github.co"
  },
  {
    "path": "internal/markdown.go",
    "chars": 1458,
    "preview": "package internal\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"log\"\n\t\"strings\"\n\n\t\"github.com/PuerkitoBio/goquery\"\n\tchromaHTML \"github.co"
  },
  {
    "path": "internal/model/generation.go",
    "chars": 451,
    "preview": "package model\n\ntype ComponentCode struct {\n\tName        string `json:\"name\"`\n\tCode        string `json:\"code,omitempty\"`"
  },
  {
    "path": "internal/settings.go",
    "chars": 1325,
    "preview": "package internal\n\nimport (\n\t\"bufio\"\n\t\"log\"\n\t\"log/slog\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n)\n\nvar Settings *AppSettings\n\nfunc New"
  },
  {
    "path": "internal/views/components/accordion.templ",
    "chars": 542,
    "preview": "// data_display\n// https://daisyui.com/components/accordion\npackage components\n\ntype AccordionRowProps struct {\n\tLabel s"
  },
  {
    "path": "internal/views/components/active_search.templ",
    "chars": 832,
    "preview": "// data_display\npackage components\n\nimport \"fmt\"\n\ntype ActiveSearchInputProps struct {\n\tID         string\n\tURL        st"
  },
  {
    "path": "internal/views/components/alert.templ",
    "chars": 1932,
    "preview": "// feedback\n// https://daisyui.com/components/alert\npackage components\n\ntempl Alert(class string) {\n\t<div role=\"alert\" c"
  },
  {
    "path": "internal/views/components/anchor.templ",
    "chars": 520,
    "preview": "// navigation\npackage components\n\ntype AnchorProps struct {\n\tHref      string\n\tLabel     string\n\tLeftIcon  templ.Compone"
  },
  {
    "path": "internal/views/components/avatar.templ",
    "chars": 630,
    "preview": "// data_display\n// https://daisyui.com/components/avatar\npackage components\n\ntype AvatarProps struct {\n\tAvatarClass     "
  },
  {
    "path": "internal/views/components/banner.templ",
    "chars": 514,
    "preview": "// layout\npackage components\n\ntype BannerProps struct {\n\tTitle       templ.Component\n\tDescription string\n}\n\ntempl Banner"
  },
  {
    "path": "internal/views/components/breadcrumbs.templ",
    "chars": 489,
    "preview": "// navigation\n// https://daisyui.com/components/breadcrumbs\npackage components\n\ntype BreadcrumbsProps []BreadcrumbsProp\n"
  },
  {
    "path": "internal/views/components/card.templ",
    "chars": 546,
    "preview": "// data_display\n// https://daisyui.com/components/card\npackage components\n\ntype CardProps struct {\n\tTitle   string\n\tCont"
  },
  {
    "path": "internal/views/components/carousel.templ",
    "chars": 463,
    "preview": "// data_display\n// https://daisyui.com/components/carousel\npackage components\n\ntype CarouselProps []CarouselProp\n\ntype C"
  },
  {
    "path": "internal/views/components/chat.templ",
    "chars": 926,
    "preview": "// data_display\n// https://daisyui.com/components/chat\npackage components\n\ntype ChatProps []ChatMessageProps\n\ntype ChatM"
  },
  {
    "path": "internal/views/components/checkbox.templ",
    "chars": 1137,
    "preview": "// data_input\n// https://daisyui.com/components/checkbox\npackage components\n\ntype CheckboxProps struct {\n\tID      string"
  },
  {
    "path": "internal/views/components/collapse.templ",
    "chars": 495,
    "preview": "// data_display\n// https://daisyui.com/components/collapse\npackage components\n\ntype CollapseProps struct {\n\tClass       "
  },
  {
    "path": "internal/views/components/combobox.templ",
    "chars": 4241,
    "preview": "// data_input\npackage components\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n)\n\ntype ComboboxProps struct {\n\tLabel    string\n\tName     s"
  },
  {
    "path": "internal/views/components/countdown.templ",
    "chars": 3941,
    "preview": "// data_display\npackage components\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\ntype CountdownProps struct {\n\tExpires time.Time\n\tDays    "
  },
  {
    "path": "internal/views/components/date_picker.templ",
    "chars": 7773,
    "preview": "// data_input\npackage components \n\nimport \"fmt\"\nimport \"time\"\n\ntype DatePickerProps struct {\n\tYear        int\n\tMonth    "
  },
  {
    "path": "internal/views/components/diff.templ",
    "chars": 590,
    "preview": "// data_display\n// https://daisyui.com/components/diff\npackage components\n\nimport \"fmt\"\n\ntype DiffProps struct {\n\tWidth "
  },
  {
    "path": "internal/views/components/drawer.templ",
    "chars": 594,
    "preview": "// layout\n// https://daisyui.com/components/drawer\npackage components\n\ntempl Drawer(toggle templ.Component, sidebar temp"
  },
  {
    "path": "internal/views/components/dropdown.templ",
    "chars": 559,
    "preview": "// actions\n// https://daisyui.com/components/dropdown\npackage components\n\ntype DropdownProps struct {\n\tLabel     string\n"
  },
  {
    "path": "internal/views/components/fab.templ",
    "chars": 700,
    "preview": "// actions\n// https://daisyui.com/components/fab\npackage components\n\ntype FABProps struct {\n\tClass       string\n\tToggle "
  },
  {
    "path": "internal/views/components/features.templ",
    "chars": 1232,
    "preview": "// data_display\npackage components\n\ntype FeaturesProps struct {\n\tTitle    string\n\tFeatures []FeatureProps\n}\n\ntype Featur"
  },
  {
    "path": "internal/views/components/file_input.templ",
    "chars": 1063,
    "preview": "// data_input\n// https://daisyui.com/components/file-input\npackage components\n\ntype FileInputProps struct {\n\tName       "
  },
  {
    "path": "internal/views/components/footer.templ",
    "chars": 1145,
    "preview": "// layout\n// https://daisyui.com/components/footer\npackage components\n\ntype FooterProps struct {\n\tIcon        templ.Comp"
  },
  {
    "path": "internal/views/components/hero.templ",
    "chars": 585,
    "preview": "// layout\n// https://daisyui.com/components/hero\npackage components\n\ntype HeroProps struct {\n\tSource  string\n\tAlt     st"
  },
  {
    "path": "internal/views/components/hover_3d_card.templ",
    "chars": 222,
    "preview": "// data_display\npackage components\n\ntempl Hover3DCard() {\n\t<div class=\"hover-3d\">\n\t\t{ children... }\n\t\t<div></div>\n\t\t<div"
  },
  {
    "path": "internal/views/components/infinite_scroll.templ",
    "chars": 708,
    "preview": "// data_display\npackage components\n\nimport \"fmt\"\n\ntempl InfiniteScrollTable(rows []templ.Component) {\n\t@Table(\n\t\t[]templ"
  },
  {
    "path": "internal/views/components/input.templ",
    "chars": 2019,
    "preview": "// data_input\npackage components\n\ntype InputProps struct {\n\t// common\n\tName            string\n\tLabel           string\n\tT"
  },
  {
    "path": "internal/views/components/lazy_load.templ",
    "chars": 236,
    "preview": "// data_display\npackage components\n\ntempl LazyLoad(url string) {\n\t<div\n\t\thx-get={ url }\n\t\thx-trigger=\"load\"\n\t\thx-target="
  },
  {
    "path": "internal/views/components/menu.templ",
    "chars": 1126,
    "preview": "// navigation\n// https://daisyui.com/components/menu\npackage components\n\ntype MenuProps struct {\n\tTitle string\n\tClass st"
  },
  {
    "path": "internal/views/components/modal.templ",
    "chars": 790,
    "preview": "// actions\n// https://daisyui.com/components/modal\npackage components\n\nimport \"fmt\"\n\ntype ModalProps struct {\n\tID    str"
  },
  {
    "path": "internal/views/components/pagination.templ",
    "chars": 2457,
    "preview": "// navigation\n// https://daisyui.com/components/pagination\npackage components\n\nimport \"fmt\"\n\ntype PaginationProps struct"
  },
  {
    "path": "internal/views/components/pricing.templ",
    "chars": 3826,
    "preview": "// data_display\npackage components\n\nimport \"slices\"\n\ntype PricingProps struct {\n\tChecked bool\n\tPrices  []PriceProps\n}\n\nt"
  },
  {
    "path": "internal/views/components/radio.templ",
    "chars": 969,
    "preview": "// data_input\n// https://daisyui.com/components/radio\npackage components\n\ntype RadioProps struct {\n\tName   string\n\tValue"
  },
  {
    "path": "internal/views/components/range.templ",
    "chars": 2429,
    "preview": "// data_input\n// https://daisyui.com/components/range\npackage components\n\nimport \"fmt\"\n\ntype RangeProps struct {\n\tID    "
  },
  {
    "path": "internal/views/components/rating.templ",
    "chars": 1213,
    "preview": "// data_input\n// https://daisyui.com/components/rating\npackage components\n\nimport \"fmt\"\n\ntype RatingProps struct {\n\tName"
  },
  {
    "path": "internal/views/components/select.templ",
    "chars": 1333,
    "preview": "// data_input\n// https://daisyui.com/components/select\npackage components\n\ntype SelectProps struct {\n\tID          string"
  },
  {
    "path": "internal/views/components/skeleton.templ",
    "chars": 306,
    "preview": "// feedback\n// https://daisyui.com/components/skeleton\npackage components\n\ntempl Skeleton() {\n\t<div class=\"flex flex-col"
  },
  {
    "path": "internal/views/components/stats.templ",
    "chars": 557,
    "preview": "// data_display\n// https://daisyui.com/components/stat\npackage components\n\ntype StatProps struct {\n\tTitle       string\n\t"
  },
  {
    "path": "internal/views/components/status.templ",
    "chars": 762,
    "preview": "// feedback\npackage components\n\nimport \"fmt\"\n\ntype StatusProps struct {\n\tCode              int\n\tTitle             string"
  },
  {
    "path": "internal/views/components/steps.templ",
    "chars": 363,
    "preview": "// navigation\n// https://daisyui.com/components/steps\npackage components\n\ntype StepProps struct {\n\tLabel string\n\tDone  b"
  },
  {
    "path": "internal/views/components/swap.templ",
    "chars": 359,
    "preview": "// actions\n// https://daisyui.com/components/swap\npackage components\n\ntype SwapProps struct {\n\tOn    templ.Component\n\tOf"
  },
  {
    "path": "internal/views/components/table.templ",
    "chars": 579,
    "preview": "// data_display\n// https://daisyui.com/components/table\npackage components\n\ntempl Table(headers []templ.Component, rows "
  },
  {
    "path": "internal/views/components/tabs.templ",
    "chars": 627,
    "preview": "// navigation\n// https://daisyui.com/components/tab\npackage components\n\ntype TabsProps struct {\n\tName         string\n\tCl"
  },
  {
    "path": "internal/views/components/testimonial.templ",
    "chars": 1214,
    "preview": "// data_display\npackage components\n\nimport \"fmt\"\n\ntype TestimonialProps []TestimonialProp\n\ntype TestimonialProp struct {"
  },
  {
    "path": "internal/views/components/text_rotate.templ",
    "chars": 379,
    "preview": "// data_display\npackage components\n\ntype TextRotateProps struct {\n\tClass string\n\tItems []TextRotateItem\n}\n\ntype TextRota"
  },
  {
    "path": "internal/views/components/textarea.templ",
    "chars": 1311,
    "preview": "// data_input\n// https://daisyui.com/components/textarea\npackage components\n\nimport \"fmt\"\n\ntype TextareaProps struct {\n\t"
  },
  {
    "path": "internal/views/components/time_slot_picker.templ",
    "chars": 5520,
    "preview": "// data_input\npackage components\n\nimport \"time\"\n\ntype TimeSlotPickerProps struct {\n\tID          string\n\tCurrentDate time"
  },
  {
    "path": "internal/views/components/timeline.templ",
    "chars": 1083,
    "preview": "// data_display\n// https://daisyui.com/components/timeline\npackage components\n\ntype TimelineProps []TimelineProp\n\ntype T"
  },
  {
    "path": "internal/views/components/toast.templ",
    "chars": 334,
    "preview": "// feedback\n// https://daisyui.com/components/toast\npackage components\n\ntype ToastProps struct {\n\tName       string\n\tToa"
  },
  {
    "path": "internal/views/components/toggle.templ",
    "chars": 1736,
    "preview": "// data_input\n// https://daisyui.com/components/toggle\npackage components\n\ntype ToggleProps struct {\n\tID        string\n\t"
  },
  {
    "path": "internal/views/components/tooltip.templ",
    "chars": 259,
    "preview": "// feedback\n// https://daisyui.com/components/tooltip\npackage components\n\ntype TooltipProps struct {\n\tTip   string\n\tClas"
  },
  {
    "path": "internal/views/custom/toast.templ",
    "chars": 2353,
    "preview": "package custom\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\ntempl ToastErrorConfirm(errs ...string) {"
  },
  {
    "path": "internal/views/embed.go",
    "chars": 86,
    "preview": "package views\n\nimport \"embed\"\n\n//go:embed components/*.templ\nvar ComponentFS embed.FS\n"
  },
  {
    "path": "internal/views/examples/accordion.templ",
    "chars": 1713,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n/*\nAccordion with input type"
  },
  {
    "path": "internal/views/examples/active_search.templ",
    "chars": 3679,
    "preview": "package examples\n\nimport (\n\t\"fmt\"\n\t\"github.com/haatos/goshipit/internal/views/components\"\n)\n\n// example\n// Active search"
  },
  {
    "path": "internal/views/examples/alert.templ",
    "chars": 1077,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Info-type alert\ntempl Ale"
  },
  {
    "path": "internal/views/examples/anchor.templ",
    "chars": 5018,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Basic anchor\ntempl BasicA"
  },
  {
    "path": "internal/views/examples/avatar.templ",
    "chars": 2107,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Multiple avatar sizes\ntem"
  },
  {
    "path": "internal/views/examples/banner.templ",
    "chars": 726,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BannerExample() {\n\t@co"
  },
  {
    "path": "internal/views/examples/breadcrumbs.templ",
    "chars": 500,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BreadcrumbsExample() {"
  },
  {
    "path": "internal/views/examples/card.templ",
    "chars": 809,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Basic card\ntempl BasicCar"
  },
  {
    "path": "internal/views/examples/carousel.templ",
    "chars": 620,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl CarouselExample() {\n\t<"
  },
  {
    "path": "internal/views/examples/chat.templ",
    "chars": 1814,
    "preview": "package examples\n\nimport (\n\t\"time\"\n\t\"github.com/haatos/goshipit/internal/views/components\"\n)\n\n// example\ntempl BasicChat"
  },
  {
    "path": "internal/views/examples/checkbox.templ",
    "chars": 1278,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Different size checkboxes"
  },
  {
    "path": "internal/views/examples/collapse.templ",
    "chars": 496,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Basic collapse\ntempl Coll"
  },
  {
    "path": "internal/views/examples/combobox.templ",
    "chars": 1056,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BasicCombobox() {\n\t<di"
  },
  {
    "path": "internal/views/examples/countdown.templ",
    "chars": 1211,
    "preview": "package examples\n\nimport (\n\t\"github.com/haatos/goshipit/internal/views/components\"\n\t\"time\"\n)\n\n// example\ntempl Countdown"
  },
  {
    "path": "internal/views/examples/date_picker.templ",
    "chars": 340,
    "preview": "package examples\n\nimport \"time\"\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BasicDat"
  },
  {
    "path": "internal/views/examples/diff.templ",
    "chars": 496,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl ImageDiff() {\n\t<div cl"
  },
  {
    "path": "internal/views/examples/drawer.templ",
    "chars": 1792,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BasicDrawer() {\n\t<div "
  },
  {
    "path": "internal/views/examples/dropdown.templ",
    "chars": 421,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BasicDropdown() {\n\t<di"
  },
  {
    "path": "internal/views/examples/fab.templ",
    "chars": 3815,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BasicFAB() {\n\t<div cla"
  },
  {
    "path": "internal/views/examples/features.templ",
    "chars": 10620,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl FeaturesExample() {\n\t@"
  },
  {
    "path": "internal/views/examples/file_input.templ",
    "chars": 608,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Different size file input"
  },
  {
    "path": "internal/views/examples/footer.templ",
    "chars": 2018,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BasicFooterWithLinks()"
  },
  {
    "path": "internal/views/examples/hero.templ",
    "chars": 1293,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BasicHero() {\n\t<div cl"
  },
  {
    "path": "internal/views/examples/hover_3d_card.templ",
    "chars": 352,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl Hover3DCardExample() {"
  },
  {
    "path": "internal/views/examples/infinite_scroll.templ",
    "chars": 613,
    "preview": "package examples\n\nimport (\n\t\"fmt\"\n\t\"github.com/haatos/goshipit/internal/views/components\"\n)\n\n// example\ntempl InfiniteSc"
  },
  {
    "path": "internal/views/examples/input.templ",
    "chars": 8683,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Different size inputs\ntem"
  },
  {
    "path": "internal/views/examples/lazy_load.templ",
    "chars": 367,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl LazyLoadExample() {\n\t@"
  },
  {
    "path": "internal/views/examples/menu.templ",
    "chars": 8945,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Basic menu\ntempl MenuExam"
  },
  {
    "path": "internal/views/examples/modal.templ",
    "chars": 3618,
    "preview": "package examples\n\nimport (\n\t\"fmt\"\n\t\"github.com/haatos/goshipit/internal/views/components\"\n)\n\n// example\n// Basic modal\nt"
  },
  {
    "path": "internal/views/examples/pagination.templ",
    "chars": 994,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BasicPaginationExample"
  },
  {
    "path": "internal/views/examples/pricing.templ",
    "chars": 4052,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Basic pricing section\ntem"
  },
  {
    "path": "internal/views/examples/radio.templ",
    "chars": 1664,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Different size radio grou"
  },
  {
    "path": "internal/views/examples/range.templ",
    "chars": 1235,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Range component using alp"
  },
  {
    "path": "internal/views/examples/rating.templ",
    "chars": 552,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Rating from 1 to 5\ntempl "
  },
  {
    "path": "internal/views/examples/select.templ",
    "chars": 2528,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Different size selects\nte"
  },
  {
    "path": "internal/views/examples/skeleton.templ",
    "chars": 189,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl SkeletonExample() {\n\t<"
  },
  {
    "path": "internal/views/examples/stats.templ",
    "chars": 621,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BasicStats() {\n\t<div c"
  },
  {
    "path": "internal/views/examples/status.templ",
    "chars": 1193,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// 404 Not Found status\ntemp"
  },
  {
    "path": "internal/views/examples/steps.templ",
    "chars": 482,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BasicSteps() {\n\t<div c"
  },
  {
    "path": "internal/views/examples/swap.templ",
    "chars": 471,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BasicSwap() {\n\t<div cl"
  },
  {
    "path": "internal/views/examples/table.templ",
    "chars": 812,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BasicTable() {\n\t@compo"
  },
  {
    "path": "internal/views/examples/tabs.templ",
    "chars": 676,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BasicTabs() {\n\t@compon"
  },
  {
    "path": "internal/views/examples/testimonial.templ",
    "chars": 5468,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl TestimonialGridExample"
  },
  {
    "path": "internal/views/examples/text_rotate.templ",
    "chars": 391,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl TextRotateExample() {\n"
  },
  {
    "path": "internal/views/examples/textarea.templ",
    "chars": 1562,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Basic textarea\ntempl Basi"
  },
  {
    "path": "internal/views/examples/time_slot_picker.templ",
    "chars": 233,
    "preview": "package examples\n\nimport \"time\"\n\n// example\n// Basic time slot picker\ntempl BasicTimeSlotPicker() {\n\t<div hx-get={ \"/tim"
  },
  {
    "path": "internal/views/examples/timeline.templ",
    "chars": 659,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\ntempl BasicTimeline() {\n\t<di"
  },
  {
    "path": "internal/views/examples/toast.templ",
    "chars": 1655,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Info-type toast\ntempl Inf"
  },
  {
    "path": "internal/views/examples/toggle.templ",
    "chars": 1453,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Different size toggles\nte"
  },
  {
    "path": "internal/views/examples/tooltip.templ",
    "chars": 632,
    "preview": "package examples\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\n// example\n// Basic tooltip at the top\n"
  },
  {
    "path": "internal/views/pages/base.templ",
    "chars": 13064,
    "preview": "package pages\n\nimport (\n\t\"fmt\"\n\t\"github.com/haatos/goshipit/internal\"\n\t\"github.com/haatos/goshipit/internal/model\"\n\t\"git"
  },
  {
    "path": "internal/views/pages/cli.templ",
    "chars": 198,
    "preview": "package pages\n\ntempl CLIPage(html string) {\n\t@SideNavLayout(nil) {\n\t\t@CLIPageMain(html)\n\t}\n}\n\ntempl CLIPageMain(html str"
  },
  {
    "path": "internal/views/pages/client_error.templ",
    "chars": 1370,
    "preview": "package pages\n\nimport \"github.com/haatos/goshipit/internal/views/components\"\n\ntempl NotFound() {\n\t@SideNavLayout(nil) {\n"
  },
  {
    "path": "internal/views/pages/component.templ",
    "chars": 2944,
    "preview": "package pages\n\nimport (\n\t\"github.com/haatos/goshipit/internal/markdown\"\n\t\"github.com/haatos/goshipit/internal/model\"\n\t\"g"
  },
  {
    "path": "internal/views/pages/index.templ",
    "chars": 20611,
    "preview": "package pages\n\nimport (\n\t\"github.com/haatos/goshipit/internal/views/components\"\n\t\"github.com/haatos/goshipit/internal/vi"
  },
  {
    "path": "internal/views/pages/server_error.templ",
    "chars": 716,
    "preview": "package pages\n\nimport (\n\t\"fmt\"\n\t\"github.com/haatos/goshipit/internal\"\n\t\"github.com/haatos/goshipit/internal/views/compon"
  },
  {
    "path": "internal/views/scripts/copy_button.templ",
    "chars": 3701,
    "preview": "package scripts\n\ntempl CodeCopyButtonScript() {\n\t<script>\n\t\tdocument.addEventListener(\"DOMContentLoaded\", function() {\n\t"
  },
  {
    "path": "package.json",
    "chars": 274,
    "preview": "{\n  \"devDependencies\": {\n    \"@tailwindcss/cli\": \"^4.1.18\",\n    \"@tailwindcss/typography\": \"^0.5.19\",\n    \"daisyui\": \"^5"
  },
  {
    "path": "readme.md",
    "chars": 3528,
    "preview": "# GoShip.it\n\nGolang + Templ + HTMX (+ TailwindCSS + DaisyUI) component library to enhance developing an application usin"
  },
  {
    "path": "tailwind.config.js",
    "chars": 699,
    "preview": "/* to disable code block CSS from tailwind/typography, we use another code highlighter */\nconst disabledCss = {\n  \"code:"
  }
]

About this extraction

This page contains the full source code of the haatos/goshipit GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 144 files (569.6 KB), approximately 207.2k tokens, and a symbol index with 392 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!