diff --git a/README.md b/README.md index 89e8cd7..fdd2d0b 100644 --- a/README.md +++ b/README.md @@ -251,9 +251,15 @@ A typical development workflow with twerge: - [func CodeGen\(g \*Generator, goPath string, cssPath string, htmlPath string, comps ...templ.Component\) error](<#CodeGen>) - [func If\(ok bool, trueClass string, falseClass string\) string](<#If>) +- [func IsDev\(\) bool](<#IsDev>) - [func It\(raw string\) string](<#It>) - [func SetDefault\(g \*Generator\)](<#SetDefault>) - [type CacheValue](<#CacheValue>) +- [type DebugHandler](<#DebugHandler>) + - [func NewDebugHandler\(\) \*DebugHandler](<#NewDebugHandler>) + - [func \(d \*DebugHandler\) Cache\(\) map\[string\]CacheValue](<#DebugHandler.Cache>) + - [func \(d \*DebugHandler\) It\(s string\) string](<#DebugHandler.It>) + - [func \(d \*DebugHandler\) SetCache\(newC map\[string\]CacheValue\)](<#DebugHandler.SetCache>) - [type Generator](<#Generator>) - [func Default\(\) \*Generator](<#Default>) - [func New\(h Handler\) \*Generator](<#New>) @@ -280,6 +286,15 @@ func If(ok bool, trueClass string, falseClass string) string If returns a short unique CSS class name from the merged classes taking an additional boolean parameter. + +## func [IsDev]() + +```go +func IsDev() bool +``` + +IsDev returns true if the default generator is using a debug handler. + ## func [It]() @@ -320,8 +335,59 @@ type CacheValue struct { } ``` + +## type [DebugHandler]() + +DebugHandler is a [Handler](<#Handler>) that can be used to debug tailwind classes. + +It is not meant to be used in production. + +It will return the same class name for the same input. + +```go +type DebugHandler struct { + // contains filtered or unexported fields +} +``` + + +### func [NewDebugHandler]() + +```go +func NewDebugHandler() *DebugHandler +``` + +NewDebugHandler creates a new DebugHandler. + + +### func \(\*DebugHandler\) [Cache]() + +```go +func (d *DebugHandler) Cache() map[string]CacheValue +``` + +Cache returns the cache of the [Generator](<#Generator>). + + +### func \(\*DebugHandler\) [It]() + +```go +func (d *DebugHandler) It(s string) string +``` + +It returns a short unique CSS class name from the merged classes. + + +### func \(\*DebugHandler\) [SetCache]() + +```go +func (d *DebugHandler) SetCache(newC map[string]CacheValue) +``` + +SetCache sets the cache of the [Generator](<#Generator>). + -## type [Generator]() +## type [Generator]() Generator generates all the code needed to use Twerge statically. @@ -341,7 +407,7 @@ func Default() *Generator Default returns the default [Generator](<#Generator>). -### func [New]() +### func [New]() ```go func New(h Handler) *Generator @@ -350,7 +416,7 @@ func New(h Handler) *Generator New creates a new Generator with the given non\-nil Handler. -### func \(Generator\) [Cache]() +### func \(Generator\) [Cache]() ```go func (Generator) Cache() map[string]CacheValue @@ -359,7 +425,7 @@ func (Generator) Cache() map[string]CacheValue Cache returns the cache of the [Generator](<#Generator>). -### func \(\*Generator\) [It]() +### func \(\*Generator\) [It]() ```go func (g *Generator) It(classes string) string @@ -372,7 +438,7 @@ If the class name already exists, it will return the existing class name. If the class name does not exist, it will generate a new class name and return it. -## type [Handler]() +## type [Handler]() Handler is the interface that needs to be implemented to customize the behavior of the [Generator](<#Generator>). diff --git a/doc/src/examples/basic.md b/doc/src/examples/basic.md index 2447b60..71b411b 100644 --- a/doc/src/examples/basic.md +++ b/doc/src/examples/basic.md @@ -15,7 +15,7 @@ simple/ ├── classes/ │ ├── classes.go # Generated Go code with class mappings │ └── classes.html # HTML output of class definitions -├── gen.go # Code generation script +├── build.go # Code generation script ├── go.mod # Go module file ├── input.css # TailwindCSS input file ├── main.go # Web server @@ -27,9 +27,9 @@ simple/ ### Code Generation -The `gen.go` file handles Twerge code generation and TailwindCSS processing: +The `build.go` file handles Twerge code generation and TailwindCSS processing: -```go title="gen.go" +```go title="build.go" //go:build ignore // +build ignore @@ -149,7 +149,7 @@ templ generate ./views 3. Run the code generation: ```sh -go run gen.go +go run build.go ``` 4. Run the server: diff --git a/doc/src/examples/complex-webapp.md b/doc/src/examples/complex-webapp.md index 0a479d3..0a53962 100644 --- a/doc/src/examples/complex-webapp.md +++ b/doc/src/examples/complex-webapp.md @@ -21,7 +21,7 @@ dashboard/ ├── classes/ │ ├── classes.go # Generated Go code with class mappings │ └── classes.html # HTML output of class definitions -├── gen.go # Code generation script +├── build.go # Code generation script ├── go.mod # Go module file ├── input.css # TailwindCSS input file ├── main.go # Web server implementation @@ -37,7 +37,7 @@ dashboard/ The dashboard example uses multiple components, all processed by Twerge: -```go title="gen.go" +```go title="build.go" //go:build ignore // +build ignore @@ -532,7 +532,7 @@ templ generate ./views 3. Run the code generation: ```sh -go run gen.go +go run build.go ``` 4. Run the server: diff --git a/doc/src/examples/tailwind-build.md b/doc/src/examples/tailwind-build.md index e50dcfd..d314271 100644 --- a/doc/src/examples/tailwind-build.md +++ b/doc/src/examples/tailwind-build.md @@ -15,7 +15,7 @@ A typical Twerge-Tailwind integration includes these steps: Here's a simple build script that handles code generation and Tailwind processing: -```go title="gen.go" +```go title="build.go" //go:build ignore // +build ignore @@ -212,7 +212,7 @@ func runBuild() { For production builds, you'll want to minify your CSS and use Tailwind's purge feature to remove unused styles: -```go title="gen_prod.go" +```go title="build_prod.go" //go:build ignore // +build ignore @@ -292,10 +292,10 @@ func runTailwind(prod bool) { Usage: ```sh # Development build -go run gen_prod.go +go run build_prod.go # Production build (minified) -go run gen_prod.go -prod +go run build_prod.go -prod ``` ## Makefile Integration @@ -307,19 +307,19 @@ You can create a Makefile to simplify common build tasks: dev: templ generate ./views - go run gen.go + go run build.go watch: go run watch.go build: templ generate ./views - go run gen.go + go run build.go go build -o app ./main.go prod: templ generate ./views - go run gen_prod.go -prod + go run build_prod.go -prod go build -o app -ldflags="-s -w" ./main.go clean: @@ -361,7 +361,7 @@ jobs: run: templ generate ./views - name: Build production CSS - run: go run gen_prod.go -prod + run: go run build_prod.go -prod - name: Build application run: go build -o app -ldflags="-s -w" ./main.go @@ -405,7 +405,7 @@ COPY . . RUN templ generate ./views # Build with Twerge -RUN go run gen_prod.go -prod +RUN go run build_prod.go -prod # Build the Go application RUN CGO_ENABLED=0 GOOS=linux go build -o app -ldflags="-s -w" ./main.go @@ -430,7 +430,7 @@ CMD ["./app"] You can extend your build script to generate multiple theme variants: -```go title="gen_themes.go" +```go title="build_themes.go" //go:build ignore // +build ignore @@ -528,10 +528,10 @@ func runTailwind(input, output string) { Usage: ```sh # Build default theme -go run gen_themes.go +go run build_themes.go # Build dark theme -go run gen_themes.go -theme dark +go run build_themes.go -theme dark ``` This example demonstrates how to integrate Twerge into your Tailwind CSS build process for both development and production environments. \ No newline at end of file diff --git a/doc/src/faq.md b/doc/src/faq.md index e4c035b..6b000a5 100644 --- a/doc/src/faq.md +++ b/doc/src/faq.md @@ -135,7 +135,7 @@ jobs: - name: Generate templ code run: templ generate ./views - name: Run Twerge code generation - run: go run ./gen.go + run: go run ./build.go - name: Build application run: go build -o app ``` diff --git a/examples/README.md b/examples/README.md index 6a290a3..60d64ba 100644 --- a/examples/README.md +++ b/examples/README.md @@ -34,7 +34,7 @@ templ generate ./views 3. Run the code generation: ```sh -go run gen.go +go run build.go ``` 4. Run the server: @@ -47,6 +47,6 @@ go run main.go ## Notes - Each example follows the same structure with `views/`, `classes/`, and `_static/` directories -- The `gen.go` file handles twerge code generation and TailwindCSS processing +- The `build.go` file handles twerge code generation and TailwindCSS processing - `classes/classes.go` contains the generated class mappings - `input.css` and `tailwind.config.js` manage TailwindCSS configuration \ No newline at end of file diff --git a/examples/dashboard/README.md b/examples/dashboard/README.md index 6626c6c..0800d58 100644 --- a/examples/dashboard/README.md +++ b/examples/dashboard/README.md @@ -17,7 +17,7 @@ templ generate 2. Run the code generation: ```sh -go run gen.go +go run build.go ``` 3. Run the server: diff --git a/examples/dashboard/gen.go b/examples/dashboard/build.go similarity index 99% rename from examples/dashboard/gen.go rename to examples/dashboard/build.go index 186d1e8..bdf8947 100644 --- a/examples/dashboard/gen.go +++ b/examples/dashboard/build.go @@ -62,4 +62,4 @@ func runTailwind() { if err := cmd.Run(); err != nil { panic(err) } -} +} \ No newline at end of file diff --git a/examples/simple/gen.go b/examples/simple/build.go similarity index 100% rename from examples/simple/gen.go rename to examples/simple/build.go diff --git a/examples/simple/views/view_templ.go b/examples/simple/views/view_templ.go new file mode 100644 index 0000000..9a9b3f6 --- /dev/null +++ b/examples/simple/views/view_templ.go @@ -0,0 +1,526 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.865 +package views + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "github.com/conneroisu/twerge" + +func View() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "stellar") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 = []any{twerge.It("bg-gray-50 text-gray-900 flex flex-col min-h-screen")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 = []any{twerge.It("bg-indigo-600 text-white shadow-md")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var4...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var6 = []any{twerge.It("container mx-auto px-4 py-4 flex justify-between items-center")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 = []any{twerge.It("flex items-center space-x-2")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var8...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var10 = []any{twerge.It("h-8 w-8")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var10...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var12 = []any{twerge.It("text-2xl font-bold")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var12...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "

stellar

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var22 = []any{twerge.It("container mx-auto px-4 py-6 flex-grow")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var22...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "
Content
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var24 = []any{twerge.It("bg-gray-800 text-white py-6")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var24...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var26 = []any{twerge.It("container mx-auto px-4")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var26...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var28 = []any{twerge.It("flex flex-col md:flex-row justify-between items-center")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var28...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var30 = []any{twerge.It("mb-4 md:mb-0")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var30...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var32 = []any{twerge.It("text-xl font-semibold")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var32...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "

stellar

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var34 = []any{twerge.It("text-gray-400")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var34...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "

Stellar Contracting Services

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var36 = []any{twerge.It("flex space-x-4")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var36...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "
  • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var38 = []any{twerge.It("text-gray-400 hover:text-white transition-colors")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var38...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "GitHub
  • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var40 = []any{twerge.It("text-gray-400 hover:text-white transition-colors")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var40...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "Documentation
  • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var42 = []any{twerge.It("text-gray-400 hover:text-white transition-colors")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var42...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "API
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var44 = []any{twerge.It("mt-4 text-center text-gray-400 text-sm")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var44...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "
© 1999 stellar. All rights reserved.
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/tw.go b/tw.go index 45c3e12..16979ba 100644 --- a/tw.go +++ b/tw.go @@ -171,13 +171,14 @@ func generateGo( "github.com/conneroisu/twerge", "CacheValue", ).Values(jen.DictFunc(func(d jen.Dict) { - for k := range g.Cache() { + keys, values := sortMap(g.Cache()) + for i, k := range keys { d[jen.Lit(k)] = jen.Qual( "github.com/conneroisu/twerge", "CacheValue", ).Values(jen.Dict{ - jen.Id("Generated"): jen.Lit(g.Cache()[k].Generated), - jen.Id("Merged"): jen.Lit(g.Cache()[k].Merged), + jen.Id("Generated"): jen.Lit(values[i].Generated), + jen.Id("Merged"): jen.Lit(values[i].Merged), }) } }))