got

package module
v0.0.0-...-d7c95ce Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 9, 2025 License: MIT Imports: 25 Imported by: 0

README

GO Theme

Go Reference Go Report Card codecov License

A Go template theme management library that provides a flexible system for organizing and rendering HTML templates with support for template inheritance, themes, and parent-child relationships.

Installation

go get github.com/gowool/got

Quick Start

package main

import (
	"errors"
	"log"
	"net/http"
	"os"
	
    "github.com/gowool/got"
)

func main() {
	// Create storage from filesystem
	storage := got.NewStorageFS(os.DirFS("themes"))

	// Create theme
	theme := got.NewTheme("default", storage)
	
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		w.WriteHeader(http.StatusOK)

		// Render template
		if err := theme.Write(r.Context(), w, "page/index.gohtml", map[string]any{
			"Title": "Hello World",
			"Content": "Welcome to GO Theme",
		}); err != nil {
			log.Println(err.Error())
		}
	})
	
	if err := http.ListenAndServe(":8080", nil); err != nil && !errors.Is(err, http.ErrServerClosed) {
		panic(err)
	}
}

Template Structure

Templates use HTML comments to define inheritance paths:

<!DOCTYPE html>
<html>
<head>
    <title>{{.Title}}</title>
</head>
<body>
    {{block "content" .}}Default content{{end}}
</body>
</html>
<!-- layouts/base.gohtml -->

{{define "content"}}
    <h1>{{.Title}}</h1>
    <p>{{.Content}}</p>
{{end}}

Theme Inheritance

Create parent-child theme relationships:

parent := got.NewTheme("default", storage)
child := got.NewTheme("custom", storage)
child.SetParent(parent)

// Child theme will fallback to parent for missing templates

Storage Backends

Filesystem Storage
storage := got.NewStorageFS(os.DirFS("themes"))
Memory Storage
storage := got.NewStorageMemory()
storage.SetTemplate("theme", "template.html", "content")
Chain Storage
chain := got.NewStorageChain()
chain.Add(memoryStorage)
chain.Add(fsStorage)

License

This project is licensed under the MIT License - see the LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrTemplateNotFound = errors.New("template not found")
View Source
var Funcs = template.FuncMap{
	"ternary": func(condition bool, trueValue, falseValue any) any {
		if condition {
			return trueValue
		}
		return falseValue
	},
	"empty": func(given any) bool {
		g := reflect.ValueOf(given)
		if !g.IsValid() {
			return true
		}
		switch g.Kind() {
		case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
			return g.IsNil() || g.IsZero() || (g.Len() == 0)
		default:
			return g.IsZero()
		}
	},
	"escape": html.EscapeString,
	"deref": func(s any) any {
		v := reflect.ValueOf(s)
		if v.Kind() == reflect.Pointer && !v.IsNil() {
			return v.Elem().Interface()
		}
		return s
	},
	"dump": spew.Sdump,

	"mul": func(inputs ...any) any {
		return doArithmetic(inputs, '*')
	},
	"div": func(inputs ...any) any {
		return doArithmetic(inputs, '/')
	},
	"add": func(inputs ...any) any {
		return doArithmetic(inputs, '+')
	},
	"sub": func(inputs ...any) any {
		return doArithmetic(inputs, '-')
	},

	"to_js":             func(str string) template.JS { return template.JS(str) },
	"to_css":            func(str string) template.CSS { return template.CSS(str) },
	"to_html":           func(str string) template.HTML { return template.HTML(str) },
	"to_html_attr":      func(str string) template.HTMLAttr { return template.HTMLAttr(str) },
	"to_int":            cast.ToInt,
	"to_uint":           cast.ToUint,
	"to_int64":          cast.ToInt64,
	"to_uint64":         cast.ToUint64,
	"to_int32":          cast.ToInt32,
	"to_uint32":         cast.ToUint32,
	"to_int16":          cast.ToInt16,
	"to_uint16":         cast.ToUint16,
	"to_int8":           cast.ToInt8,
	"to_uint8":          cast.ToUint8,
	"to_float64":        cast.ToFloat64,
	"to_float32":        cast.ToFloat32,
	"to_bool":           cast.ToBool,
	"to_string":         cast.ToString,
	"to_time":           cast.ToTime,
	"to_duration":       cast.ToDuration,
	"to_slice":          cast.ToSlice,
	"to_string_slice":   cast.ToStringSlice,
	"to_float64_slice":  cast.ToFloat64Slice,
	"to_int64_slice":    cast.ToInt64Slice,
	"to_int_slice":      cast.ToIntSlice,
	"to_uint_slice":     cast.ToUintSlice,
	"to_bool_slice":     cast.ToBoolSlice,
	"to_duration_slice": cast.ToDurationSlice,

	"str_build": func(str ...string) string {
		var b strings.Builder
		for _, s := range str {
			b.WriteString(s)
		}
		return b.String()
	},
	"str_camelcase":   camelcase.Camelcase,
	"str_snakecase":   snakecase.Snakecase,
	"str_trim_space":  strings.TrimSpace,
	"str_trim_left":   strings.TrimLeft,
	"str_trim_right":  strings.TrimRight,
	"str_trim_prefix": strings.TrimPrefix,
	"str_trim_suffix": strings.TrimSuffix,
	"str_has_prefix":  strings.HasPrefix,
	"str_has_suffix":  strings.HasSuffix,
	"str_upper":       strings.ToUpper,
	"str_lower":       strings.ToLower,
	"str_title":       strings.ToTitle,
	"str_contains":    strings.Contains,
	"str_replace":     strings.ReplaceAll,
	"str_equal":       strings.EqualFold,
	"str_index":       strings.Index,
	"str_join":        strings.Join,
	"str_split":       strings.Split,
	"str_split_n":     strings.SplitN,
	"str_fields":      strings.Fields,
	"str_repeat":      strings.Repeat,
	"str_len":         func(s string) int { return utf8.RuneCountInString(s) },

	"json": func(v any) string {
		return encode(v, json.Marshal)
	},
	"xml": func(v any) string {
		return encode(v, xml.Marshal)
	},
	"yaml": func(v any) string {
		defer func() { _ = recover() }()
		var buf bytes.Buffer
		enc := yaml.NewEncoder(&buf)
		if err := enc.Encode(v); err != nil {
			return ""
		}
		return template.JSEscapeString(internal.String(buf.Bytes()))
	},
	"json_pretty": func(v any) string {
		return pretty(v, json.MarshalIndent)
	},
	"xml_pretty": func(v any) string {
		return pretty(v, xml.MarshalIndent)
	},
	"yaml_pretty": func(v any) string {
		defer func() { _ = recover() }()
		var buf bytes.Buffer
		enc := yaml.NewEncoder(&buf)
		enc.SetIndent(2)
		if err := enc.Encode(v); err != nil {
			return ""
		}
		return template.JSEscapeString(internal.String(buf.Bytes()))
	},

	"seq":      internal.Seq,
	"list":     func(v ...any) []any { return v },
	"first":    func(v []any) any { return v[0] },
	"last":     func(v []any) any { return v[len(v)-1] },
	"append":   func(v []any, e ...any) []any { return append(v, e...) },
	"prepend":  func(v []any, e ...any) []any { return append(e, v...) },
	"reverse":  func(v []any) []any { slices.Reverse(v); return v },
	"repeat":   func(v []any, count int) []any { return slices.Repeat(v, count) },
	"contains": func(v []any, i any) bool { return slices.Contains(v, i) },
	"index_of": func(v []any, i any) int { return slices.Index(v, i) },
	"concat":   func(sl ...[]any) []any { return slices.Concat(sl...) },

	"dict": func(v ...any) map[any]any {
		if len(v)%2 != 0 {
			v = append(v, "")
		}
		dict := make(map[any]any, len(v)/2)
		for i := 0; i < len(v); i += 2 {
			dict[v[i]] = v[i+1]
		}
		return dict
	},
	"keys":   func(m map[any]any) []any { return slices.Collect(maps.Keys(m)) },
	"values": func(m map[any]any) []any { return slices.Collect(maps.Values(m)) },
	"has":    func(m map[any]any, k any) bool { _, ok := m[k]; return ok },
	"get":    func(m map[any]any, k any) any { return m[k] },
	"set":    func(m map[any]any, k, v any) map[any]any { m[k] = v; return m },
	"unset":  func(m map[any]any, k any) map[any]any { delete(m, k); return m },

	"now":  time.Now,
	"date": FormatDate,
	"date_local": func(fmt string, date any) string {
		return FormatDate(fmt, date, "Local")
	},
	"date_utc": func(fmt string, date any) string {
		return FormatDate(fmt, date, "UTC")
	},
}

Functions

func FormatDate

func FormatDate(fmt string, date any, location string) string

Types

type Storage

type Storage interface {
	// Find returns a template by its theme and name.
	//
	// If the template is not found, it returns ErrTemplateNotFound.
	Find(ctx context.Context, theme, name string) (Template, error)
}

Storage is an interface for loading templates from a storage.

type StorageChain

type StorageChain struct {
	// contains filtered or unexported fields
}

StorageChain is a storage implementation that chains multiple storages together.

func NewStorageChain

func NewStorageChain(storages ...Storage) *StorageChain

func (*StorageChain) Add

func (s *StorageChain) Add(storage Storage)

func (*StorageChain) Find

func (s *StorageChain) Find(ctx context.Context, theme, name string) (Template, error)

type StorageFS

type StorageFS struct {
	// contains filtered or unexported fields
}

StorageFS is a storage implementation that loads templates from a filesystem.

func NewStorageFS

func NewStorageFS(fsys fs.FS) *StorageFS

func (*StorageFS) Find

func (s *StorageFS) Find(_ context.Context, theme, name string) (Template, error)

type StorageMemory

type StorageMemory struct {
	// contains filtered or unexported fields
}

StorageMemory is a storage implementation that stores templates in memory.

func NewStorageMemory

func NewStorageMemory() *StorageMemory

func (*StorageMemory) Add

func (s *StorageMemory) Add(theme, name, content string)

func (*StorageMemory) Find

func (s *StorageMemory) Find(_ context.Context, theme, name string) (Template, error)

type Template

type Template interface {
	Theme() string
	Path() string
	Name() string
	Content() string
}

type Theme

type Theme struct {
	// contains filtered or unexported fields
}

func NewTheme

func NewTheme(name string, storage Storage) *Theme

func (*Theme) AddFuncMap

func (t *Theme) AddFuncMap(funcMap template.FuncMap)

func (*Theme) Clear

func (t *Theme) Clear()

func (*Theme) Debug

func (t *Theme) Debug() bool

func (*Theme) FuncMap

func (t *Theme) FuncMap() template.FuncMap

func (*Theme) Name

func (t *Theme) Name() string

func (*Theme) Parent

func (t *Theme) Parent() *Theme

func (*Theme) SetDebug

func (t *Theme) SetDebug(debug bool)

func (*Theme) SetFuncMap

func (t *Theme) SetFuncMap(funcMap template.FuncMap)

func (*Theme) SetParent

func (t *Theme) SetParent(parent *Theme)

func (*Theme) Write

func (t *Theme) Write(ctx context.Context, w io.Writer, name string, data any) error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL