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:
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
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.