├── .github └── workflows │ └── go.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── cmd └── storybook.go ├── css.go ├── go.mod ├── go.sum ├── icons ├── icons.templ └── icons_templ.go ├── include.templ ├── include_templ.go ├── primitives ├── dialog │ ├── close.templ │ ├── close_templ.go │ ├── content.templ │ ├── content_templ.go │ ├── description.templ │ ├── description_templ.go │ ├── dialog.go │ ├── overlay.templ │ ├── overlay_templ.go │ ├── root.templ │ ├── root_templ.go │ ├── title.templ │ ├── title_templ.go │ ├── trigger.templ │ └── trigger_templ.go ├── portal │ ├── root.templ │ └── root_templ.go ├── props.go └── utils.go ├── static └── css │ ├── input.css │ └── output.css ├── tailwind.config.js ├── tailwindcss-animate.js └── ui ├── accordion.templ ├── accordion_templ.go ├── alert.templ ├── alert_templ.go ├── aspect-ratio ├── generated_optaliase.go ├── root.templ └── root_templ.go ├── avatar.templ ├── avatar_templ.go ├── badge.templ ├── badge_templ.go ├── breadcrumb.templ ├── breadcrumb_templ.go ├── button.templ ├── button ├── root.templ └── root_templ.go ├── button_templ.go ├── card.templ ├── card_templ.go ├── checkbox.templ ├── checkbox_templ.go ├── collapsible.templ ├── collapsible_templ.go ├── dialog.templ ├── dialog ├── close.go ├── content.templ ├── content_templ.go ├── description.templ ├── description_templ.go ├── footer.templ ├── footer_templ.go ├── header.templ ├── header_templ.go ├── overlay.templ ├── overlay_templ.go ├── root.go ├── title.templ ├── title_templ.go └── trigger.go ├── dialog_templ.go ├── dropdown-menu.templ ├── dropdown-menu_templ.go ├── field.templ ├── field_templ.go ├── input.templ ├── input_templ.go ├── label.templ ├── label_templ.go ├── optalias_generator.go ├── progress ├── generated_optaliase.go ├── root.templ └── root_templ.go ├── props.go ├── separator.templ ├── separator_templ.go ├── skeleton.templ ├── skeleton_templ.go ├── switch.templ ├── switch_templ.go ├── table.templ ├── table_templ.go ├── tabs.templ ├── tabs_templ.go ├── textarea.templ ├── textarea_templ.go ├── toggle.templ ├── toggle_templ.go └── utils.go /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a golang project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go 3 | 4 | name: Go 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | jobs: 13 | 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Set up Go 20 | uses: actions/setup-go@v4 21 | with: 22 | go-version: '1.23.2' 23 | 24 | - name: Build 25 | run: go build -v ./... 26 | 27 | - name: Test 28 | run: go test -v ./... 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # Go workspace file 21 | go.work 22 | go.work.sum 23 | 24 | # env file 25 | .env 26 | 27 | *storybook.log 28 | 29 | storybook-server/ 30 | 31 | tailwindcss 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Rotem Horesh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | gen: 2 | templ generate 3 | ./tailwindcss -i ./static/css/input.css -o ./static/css/output.css --minify 4 | go generate ./... 5 | 6 | sb: 7 | go run ./cmd/storybook.go 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shadcn/ui port for Go + Templ + Alpine.js + Tailwind CSS 2 | 3 | [![Go Reference](https://pkg.go.dev/badge/github.com/rotemhoresh/shadcn-templ.svg)](https://pkg.go.dev/github.com/rotemhoresh/shadcn-templ) 4 | [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) 5 | [![Go Report Card](https://goreportcard.com/badge/github.com/rotemhoresh/shadcn-templ)](https://goreportcard.com/report/github.com/rotemhoresh/shadcn-templ) 6 | 7 | ### Note 8 | 9 | **The codebase is going through a change in structure, so it's currently a bit messy** 10 | 11 | This is a work in proccess. 12 | 13 | - Not all the components from shadcn/ui are implemented. 14 | - There are refinements needed for some of the components - alpine.js naming, unfinished accessibility, improvements I want to make, etc. 15 | - Some components might contain behavior that existed for previous needs (I detached the developement of this from another project). Hopefully will be fixed in the future. 16 | 17 | ## Overview 18 | 19 | A [shadcn/ui](https://ui.shadcn.com/) port using [Go](https://go.dev/), [Templ](https://templ.guide/), [Alpine.js](https://alpinejs.dev/) and [Tailwind CSS](https://tailwindcss.com/). 20 | 21 | ### Components 22 | 23 | [issue](https://github.com/rotemhoresh/shadcn-templ/issues/1#issue-2570468143). 24 | 25 | ### Roadmap 26 | 27 | - Adding all the components from shadcn/ui 28 | - Making sure the components are of good quality: Accessibility, Correct functionality, Style, etc. 29 | - Creating a CLI to have a flow similar to shadcn's. 30 | 31 | ### Usage 32 | 33 | You have to include the [Head](https://github.com/rotemhoresh/shadcn-templ/blob/main/include.templ#L4) component in your `head` tag (it includes the neccessery scripts - Alpine.js and a theme script). 34 | You have to serve the [CSS](https://github.com/rotemhoresh/shadcn-templ/blob/main/css.go#L10) var and link to it in your `head` tag. 35 | 36 | Example: 37 | 38 | ```go 39 | router.HandleFunc("GET /static/css/styles.css", func(w http.ResponseWriter, r *http.Request) { 40 | w.Header().Set("Content-Type", "text/css") 41 | w.Write(shadcntempl.CSS) 42 | }) 43 | ``` 44 | 45 | ```templ 46 | templ Layout() { 47 | 48 | 49 | 50 | // ... 51 | @shadcntempl.Head() 52 | 53 | 54 | 55 | { children... } 56 | 57 | 58 | 59 | } 60 | ``` 61 | 62 | ### Example 63 | 64 | Use in `.templ` files. 65 | 66 | ```templ 67 | import "github.com/rotemhoresh/shadcn-templ/ui/button" 68 | 69 | templ Page() { 70 | @button.Root(button.RootProps{}) { 71 | Click me 72 | } 73 | } 74 | ``` 75 | 76 | ### Design 77 | 78 | The components props (parameters) is structures like this: 79 | 80 | ```go 81 | type Props struct { 82 | 83 | p.CoreProps // Class and Attrs 84 | } 85 | ``` 86 | 87 | For example, the `button.Root`'s props: 88 | 89 | ```go 90 | type RootProps struct { 91 | Type Type // default: [TypeButton] 92 | Variant Variant // default: [VariantDefault] 93 | Size Size // default: [SizeDefault] 94 | p.CoreProps 95 | } 96 | ``` 97 | 98 | The components are written with constant referencing to the shadcn/ui source code and the underlying radix components. 99 | 100 | ## Contributing 101 | 102 | Contributions are welcome for both new components and improvements for existing ones. 103 | 104 | Make sure to read the README and go over the codebase to understand the design choices and overall coding style as well as getting familiar with shadcn/ui. 105 | 106 | ### License 107 | 108 | MIT 109 | -------------------------------------------------------------------------------- /cmd/storybook.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "net/url" 7 | 8 | "github.com/a-h/templ/storybook" 9 | "github.com/rotemhoresh/shadcn-templ/ui/button" 10 | ) 11 | 12 | func main() { 13 | s := storybook.New(storybook.WithHeader(` 14 | 15 | 16 | `)) 17 | s.AddComponent("button", button.Root, storybook.Arg{ 18 | Name: "content", 19 | Value: "val", 20 | Control: "con", 21 | Get: func(q url.Values) interface{} { 22 | return q.Get("content") 23 | }, 24 | }) 25 | 26 | // if err := s.Build(context.Background()); err != nil { 27 | // log.Fatalln(err) 28 | // } 29 | 30 | if err := s.ListenAndServeWithContext(context.Background()); err != nil { 31 | log.Fatalln(err) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /css.go: -------------------------------------------------------------------------------- 1 | package shadcntempl 2 | 3 | import _ "embed" 4 | 5 | // The compiled CSS used in this module. 6 | // 7 | // You need to include a path that serves this in your head tag. 8 | // 9 | //go:embed static/css/output.css 10 | var CSS []byte 11 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rotemhoresh/shadcn-templ 2 | 3 | go 1.23.2 4 | 5 | require ( 6 | github.com/Oudwins/tailwind-merge-go v0.2.0 7 | github.com/a-h/templ v0.2.778 8 | ) 9 | 10 | require ( 11 | github.com/a-h/pathvars v0.0.14 // indirect 12 | github.com/rs/cors v1.11.0 // indirect 13 | go.uber.org/multierr v1.11.0 // indirect 14 | go.uber.org/zap v1.27.0 // indirect 15 | golang.org/x/mod v0.20.0 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Oudwins/tailwind-merge-go v0.2.0 h1:rtVHgYmLwwae4P+K6//ceRuUdyz3Bny6fo4664fOEmo= 2 | github.com/Oudwins/tailwind-merge-go v0.2.0/go.mod h1:kkZodgOPvZQ8f7SIrlWkG/w1g9JTbtnptnePIh3V72U= 3 | github.com/a-h/pathvars v0.0.14 h1:5/C0U5zuUtvAfVQCR5vow4E4MIRU7QIOLz8z26EeeQw= 4 | github.com/a-h/pathvars v0.0.14/go.mod h1:7rLTtvDVyKneR/N65hC0lh2sZ2KRyAmWFaOvv00uxb0= 5 | github.com/a-h/templ v0.2.778 h1:VzhOuvWECrwOec4790lcLlZpP4Iptt5Q4K9aFxQmtaM= 6 | github.com/a-h/templ v0.2.778/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= 7 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 8 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 9 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 10 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 11 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 12 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 13 | github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= 14 | github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= 15 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 16 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 17 | go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= 18 | go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= 19 | go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= 20 | go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 21 | go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= 22 | go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= 23 | golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= 24 | golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 25 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 26 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 27 | -------------------------------------------------------------------------------- /icons/icons.templ: -------------------------------------------------------------------------------- 1 | package icons 2 | 3 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 4 | 5 | type Props struct { 6 | Class string 7 | Attrs templ.Attributes 8 | } 9 | 10 | templ CircleAlert(props Props) { 11 | 12 | } 13 | 14 | templ CircleCheck(props Props) { 15 | 16 | } 17 | 18 | templ Check(props Props) { 19 | 20 | } 21 | 22 | templ Info(props Props) { 23 | 24 | } 25 | 26 | templ CircleX(props Props) { 27 | 28 | } 29 | 30 | templ Megaphone(props Props) { 31 | 32 | } 33 | 34 | templ ChevronRight(props Props) { 35 | 36 | } 37 | 38 | templ LogIn(props Props) { 39 | 40 | } 41 | 42 | templ Film(props Props) { 43 | 44 | } 45 | 46 | templ Sun(props Props) { 47 | 48 | } 49 | 50 | templ Moon(props Props) { 51 | 52 | } 53 | 54 | templ SunMoon(props Props) { 55 | 56 | } 57 | 58 | templ ChevronDown(props Props) { 59 | 60 | } 61 | 62 | templ ChevronUp(props Props) { 63 | 64 | } 65 | 66 | templ X(props Props) { 67 | 68 | } 69 | -------------------------------------------------------------------------------- /include.templ: -------------------------------------------------------------------------------- 1 | package shadcntempl 2 | 3 | // Tags to include in the head of your page. 4 | templ Head() { 5 | // Alpine.js 6 | 7 | 8 | 9 | // Dark mode 10 | 17 | } 18 | -------------------------------------------------------------------------------- /include_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package shadcntempl 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | // Tags to include in the head of your page. 12 | func Head() templ.Component { 13 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 14 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 15 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 16 | return templ_7745c5c3_CtxErr 17 | } 18 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 19 | if !templ_7745c5c3_IsBuffer { 20 | defer func() { 21 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 22 | if templ_7745c5c3_Err == nil { 23 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 24 | } 25 | }() 26 | } 27 | ctx = templ.InitializeContext(ctx) 28 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 29 | if templ_7745c5c3_Var1 == nil { 30 | templ_7745c5c3_Var1 = templ.NopComponent 31 | } 32 | ctx = templ.ClearChildren(ctx) 33 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 34 | if templ_7745c5c3_Err != nil { 35 | return templ_7745c5c3_Err 36 | } 37 | return templ_7745c5c3_Err 38 | }) 39 | } 40 | 41 | var _ = templruntime.GeneratedTemplate 42 | -------------------------------------------------------------------------------- /primitives/dialog/close.templ: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import "fmt" 4 | 5 | // There is no element for dialog close, just add these attributes to your component. 6 | var Close = templ.Attributes{ 7 | "x-on:click": fmt.Sprintf("%s = false", control), 8 | } 9 | -------------------------------------------------------------------------------- /primitives/dialog/close_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package dialog 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import "fmt" 12 | 13 | // There is no element for dialog close, just add these attributes to your component. 14 | var Close = templ.Attributes{ 15 | "x-on:click": fmt.Sprintf("%s = false", control), 16 | } 17 | 18 | var _ = templruntime.GeneratedTemplate 19 | -------------------------------------------------------------------------------- /primitives/dialog/content.templ: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import ( 4 | "fmt" 5 | p "github.com/rotemhoresh/shadcn-templ/primitives" 6 | ) 7 | 8 | const contentName = "content" 9 | 10 | type ContentProps struct { 11 | p.CoreProps 12 | } 13 | 14 | templ Content(props ContentProps) { 15 | 32 | } 33 | -------------------------------------------------------------------------------- /primitives/dialog/content_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package dialog 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | "fmt" 13 | p "github.com/rotemhoresh/shadcn-templ/primitives" 14 | ) 15 | 16 | const contentName = "content" 17 | 18 | type ContentProps struct { 19 | p.CoreProps 20 | } 21 | 22 | func Content(props ContentProps) templ.Component { 23 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 24 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 25 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 26 | return templ_7745c5c3_CtxErr 27 | } 28 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 29 | if !templ_7745c5c3_IsBuffer { 30 | defer func() { 31 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 32 | if templ_7745c5c3_Err == nil { 33 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 34 | } 35 | }() 36 | } 37 | ctx = templ.InitializeContext(ctx) 38 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 39 | if templ_7745c5c3_Var1 == nil { 40 | templ_7745c5c3_Var1 = templ.NopComponent 41 | } 42 | ctx = templ.ClearChildren(ctx) 43 | var templ_7745c5c3_Var2 = []any{props.Class} 44 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 45 | if templ_7745c5c3_Err != nil { 46 | return templ_7745c5c3_Err 47 | } 48 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 174 | if templ_7745c5c3_Err != nil { 175 | return templ_7745c5c3_Err 176 | } 177 | templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) 178 | if templ_7745c5c3_Err != nil { 179 | return templ_7745c5c3_Err 180 | } 181 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 182 | if templ_7745c5c3_Err != nil { 183 | return templ_7745c5c3_Err 184 | } 185 | return templ_7745c5c3_Err 186 | }) 187 | } 188 | 189 | var _ = templruntime.GeneratedTemplate 190 | -------------------------------------------------------------------------------- /primitives/dialog/description.templ: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import p "github.com/rotemhoresh/shadcn-templ/primitives" 4 | 5 | const descriptionName = "description" 6 | 7 | type DescriptionProps struct { 8 | p.CoreProps 9 | } 10 | 11 | templ Description(props DescriptionProps) { 12 |

17 | { children... } 18 |

19 | } 20 | -------------------------------------------------------------------------------- /primitives/dialog/description_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package dialog 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import p "github.com/rotemhoresh/shadcn-templ/primitives" 12 | 13 | const descriptionName = "description" 14 | 15 | type DescriptionProps struct { 16 | p.CoreProps 17 | } 18 | 19 | func Description(props DescriptionProps) templ.Component { 20 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 21 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 22 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 23 | return templ_7745c5c3_CtxErr 24 | } 25 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 26 | if !templ_7745c5c3_IsBuffer { 27 | defer func() { 28 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 29 | if templ_7745c5c3_Err == nil { 30 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 31 | } 32 | }() 33 | } 34 | ctx = templ.InitializeContext(ctx) 35 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 36 | if templ_7745c5c3_Var1 == nil { 37 | templ_7745c5c3_Var1 = templ.NopComponent 38 | } 39 | ctx = templ.ClearChildren(ctx) 40 | var templ_7745c5c3_Var2 = []any{props.Class} 41 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 42 | if templ_7745c5c3_Err != nil { 43 | return templ_7745c5c3_Err 44 | } 45 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") 80 | if templ_7745c5c3_Err != nil { 81 | return templ_7745c5c3_Err 82 | } 83 | templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) 84 | if templ_7745c5c3_Err != nil { 85 | return templ_7745c5c3_Err 86 | } 87 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") 88 | if templ_7745c5c3_Err != nil { 89 | return templ_7745c5c3_Err 90 | } 91 | return templ_7745c5c3_Err 92 | }) 93 | } 94 | 95 | var _ = templruntime.GeneratedTemplate 96 | -------------------------------------------------------------------------------- /primitives/dialog/dialog.go: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import ( 4 | "fmt" 5 | 6 | p "github.com/rotemhoresh/shadcn-templ/primitives" 7 | ) 8 | 9 | const scopeName = "dialog" 10 | 11 | var control = p.Prop("open") 12 | 13 | func getState(c string) string { 14 | return fmt.Sprintf("%s ? 'open' : 'closed'", c) 15 | } 16 | -------------------------------------------------------------------------------- /primitives/dialog/overlay.templ: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import p "github.com/rotemhoresh/shadcn-templ/primitives" 4 | 5 | type OverlayProps struct { 6 | p.CoreProps 7 | } 8 | 9 | templ Overlay(props OverlayProps) { 10 |
18 | { children... } 19 |
20 | } 21 | -------------------------------------------------------------------------------- /primitives/dialog/overlay_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package dialog 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import p "github.com/rotemhoresh/shadcn-templ/primitives" 12 | 13 | type OverlayProps struct { 14 | p.CoreProps 15 | } 16 | 17 | func Overlay(props OverlayProps) templ.Component { 18 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 19 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 20 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 21 | return templ_7745c5c3_CtxErr 22 | } 23 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 24 | if !templ_7745c5c3_IsBuffer { 25 | defer func() { 26 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 27 | if templ_7745c5c3_Err == nil { 28 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 29 | } 30 | }() 31 | } 32 | ctx = templ.InitializeContext(ctx) 33 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 34 | if templ_7745c5c3_Var1 == nil { 35 | templ_7745c5c3_Var1 = templ.NopComponent 36 | } 37 | ctx = templ.ClearChildren(ctx) 38 | var templ_7745c5c3_Var2 = []any{props.Class} 39 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 40 | if templ_7745c5c3_Err != nil { 41 | return templ_7745c5c3_Err 42 | } 43 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 91 | if templ_7745c5c3_Err != nil { 92 | return templ_7745c5c3_Err 93 | } 94 | templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) 95 | if templ_7745c5c3_Err != nil { 96 | return templ_7745c5c3_Err 97 | } 98 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 99 | if templ_7745c5c3_Err != nil { 100 | return templ_7745c5c3_Err 101 | } 102 | return templ_7745c5c3_Err 103 | }) 104 | } 105 | 106 | var _ = templruntime.GeneratedTemplate 107 | -------------------------------------------------------------------------------- /primitives/dialog/root.templ: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import ( 4 | "fmt" 5 | twmerge "github.com/Oudwins/tailwind-merge-go" 6 | p "github.com/rotemhoresh/shadcn-templ/primitives" 7 | ) 8 | 9 | // TODO: support controlled dialog state 10 | // TODO: add a modal prop 11 | 12 | type RootProps struct { 13 | p.CoreProps 14 | } 15 | 16 | templ Root(props RootProps) { 17 |
25 | { children... } 26 |
27 | } 28 | -------------------------------------------------------------------------------- /primitives/dialog/root_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package dialog 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | "fmt" 13 | twmerge "github.com/Oudwins/tailwind-merge-go" 14 | p "github.com/rotemhoresh/shadcn-templ/primitives" 15 | ) 16 | 17 | // TODO: support controlled dialog state 18 | // TODO: add a modal prop 19 | 20 | type RootProps struct { 21 | p.CoreProps 22 | } 23 | 24 | func Root(props RootProps) templ.Component { 25 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 26 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 27 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 28 | return templ_7745c5c3_CtxErr 29 | } 30 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 31 | if !templ_7745c5c3_IsBuffer { 32 | defer func() { 33 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 34 | if templ_7745c5c3_Err == nil { 35 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 36 | } 37 | }() 38 | } 39 | ctx = templ.InitializeContext(ctx) 40 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 41 | if templ_7745c5c3_Var1 == nil { 42 | templ_7745c5c3_Var1 = templ.NopComponent 43 | } 44 | ctx = templ.ClearChildren(ctx) 45 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(props.Class)} 46 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 47 | if templ_7745c5c3_Err != nil { 48 | return templ_7745c5c3_Err 49 | } 50 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 100 | if templ_7745c5c3_Err != nil { 101 | return templ_7745c5c3_Err 102 | } 103 | templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) 104 | if templ_7745c5c3_Err != nil { 105 | return templ_7745c5c3_Err 106 | } 107 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 108 | if templ_7745c5c3_Err != nil { 109 | return templ_7745c5c3_Err 110 | } 111 | return templ_7745c5c3_Err 112 | }) 113 | } 114 | 115 | var _ = templruntime.GeneratedTemplate 116 | -------------------------------------------------------------------------------- /primitives/dialog/title.templ: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import p "github.com/rotemhoresh/shadcn-templ/primitives" 4 | 5 | const titleName = "title" 6 | 7 | type TitleProps struct { 8 | p.CoreProps 9 | } 10 | 11 | templ Title(props TitleProps) { 12 |

17 | { children... } 18 |

19 | } 20 | -------------------------------------------------------------------------------- /primitives/dialog/title_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package dialog 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import p "github.com/rotemhoresh/shadcn-templ/primitives" 12 | 13 | const titleName = "title" 14 | 15 | type TitleProps struct { 16 | p.CoreProps 17 | } 18 | 19 | func Title(props TitleProps) templ.Component { 20 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 21 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 22 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 23 | return templ_7745c5c3_CtxErr 24 | } 25 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 26 | if !templ_7745c5c3_IsBuffer { 27 | defer func() { 28 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 29 | if templ_7745c5c3_Err == nil { 30 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 31 | } 32 | }() 33 | } 34 | ctx = templ.InitializeContext(ctx) 35 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 36 | if templ_7745c5c3_Var1 == nil { 37 | templ_7745c5c3_Var1 = templ.NopComponent 38 | } 39 | ctx = templ.ClearChildren(ctx) 40 | var templ_7745c5c3_Var2 = []any{props.Class} 41 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 42 | if templ_7745c5c3_Err != nil { 43 | return templ_7745c5c3_Err 44 | } 45 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") 80 | if templ_7745c5c3_Err != nil { 81 | return templ_7745c5c3_Err 82 | } 83 | templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) 84 | if templ_7745c5c3_Err != nil { 85 | return templ_7745c5c3_Err 86 | } 87 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") 88 | if templ_7745c5c3_Err != nil { 89 | return templ_7745c5c3_Err 90 | } 91 | return templ_7745c5c3_Err 92 | }) 93 | } 94 | 95 | var _ = templruntime.GeneratedTemplate 96 | -------------------------------------------------------------------------------- /primitives/dialog/trigger.templ: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import ( 4 | "fmt" 5 | p "github.com/rotemhoresh/shadcn-templ/primitives" 6 | ) 7 | 8 | // There is no element for dialog trigger, just add these attributes to your component. 9 | var Trigger = templ.Attributes{ 10 | "aria-haspopup": "dialog", 11 | ":aria-expanded": control, 12 | ":aria-controls": p.Id(scopeName, contentName), 13 | ":data-state": getState(control), 14 | "x-on:click": fmt.Sprintf("%s = true", control), 15 | } 16 | -------------------------------------------------------------------------------- /primitives/dialog/trigger_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package dialog 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | "fmt" 13 | p "github.com/rotemhoresh/shadcn-templ/primitives" 14 | ) 15 | 16 | // There is no element for dialog trigger, just add these attributes to your component. 17 | var Trigger = templ.Attributes{ 18 | "aria-haspopup": "dialog", 19 | ":aria-expanded": control, 20 | ":aria-controls": p.Id(scopeName, contentName), 21 | ":data-state": getState(control), 22 | "x-on:click": fmt.Sprintf("%s = true", control), 23 | } 24 | 25 | var _ = templruntime.GeneratedTemplate 26 | -------------------------------------------------------------------------------- /primitives/portal/root.templ: -------------------------------------------------------------------------------- 1 | package portal 2 | 3 | const DefaultSelector = "body" 4 | 5 | type RootProps struct { 6 | Selector string 7 | Attrs templ.Attributes 8 | } 9 | 10 | func Root(props RootProps) templ.Component { 11 | if props.Selector == "" { 12 | props.Selector = DefaultSelector 13 | } 14 | return root(props) 15 | } 16 | 17 | templ root(props RootProps) { 18 | 24 | } 25 | -------------------------------------------------------------------------------- /primitives/portal/root_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package portal 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | const DefaultSelector = "body" 12 | 13 | type RootProps struct { 14 | Selector string 15 | Attrs templ.Attributes 16 | } 17 | 18 | func Root(props RootProps) templ.Component { 19 | if props.Selector == "" { 20 | props.Selector = DefaultSelector 21 | } 22 | return root(props) 23 | } 24 | 25 | func root(props RootProps) templ.Component { 26 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 27 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 28 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 29 | return templ_7745c5c3_CtxErr 30 | } 31 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 32 | if !templ_7745c5c3_IsBuffer { 33 | defer func() { 34 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 35 | if templ_7745c5c3_Err == nil { 36 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 37 | } 38 | }() 39 | } 40 | ctx = templ.InitializeContext(ctx) 41 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 42 | if templ_7745c5c3_Var1 == nil { 43 | templ_7745c5c3_Var1 = templ.NopComponent 44 | } 45 | ctx = templ.ClearChildren(ctx) 46 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 76 | if templ_7745c5c3_Err != nil { 77 | return templ_7745c5c3_Err 78 | } 79 | return templ_7745c5c3_Err 80 | }) 81 | } 82 | 83 | var _ = templruntime.GeneratedTemplate 84 | -------------------------------------------------------------------------------- /primitives/props.go: -------------------------------------------------------------------------------- 1 | package primitives 2 | 3 | import "github.com/a-h/templ" 4 | 5 | // 6 | // type Option[T CorePropsInter] func(T) 7 | // 8 | // // Sets the class 9 | // func WithClass[T CorePropsInter](c string) Option[T] { 10 | // return func(p T) { 11 | // p.SetClass(c) 12 | // } 13 | // } 14 | // 15 | // // Sets the attributes 16 | // func WithAttrs[T CorePropsInter](a templ.Attributes) Option[T] { 17 | // return func(p T) { 18 | // p.SetAttrs(a) 19 | // } 20 | // } 21 | // 22 | // // Adds an attribute 23 | // func WithAttr[T CorePropsInter](k string, v any) Option[T] { 24 | // return func(p T) { 25 | // p.SetAttr(k, v) 26 | // } 27 | // } 28 | 29 | type CoreProps struct { 30 | Class string 31 | Attrs templ.Attributes 32 | } 33 | 34 | func (p *CoreProps) AddAttr(k string, v any) { 35 | if p.Attrs == nil { 36 | p.Attrs = templ.Attributes{} 37 | } 38 | if k != "" && v != nil { 39 | p.Attrs[k] = v 40 | } 41 | } 42 | 43 | // 44 | // // assert interface implementation 45 | // var _ CorePropsInter = (*CoreProps)(nil) 46 | // 47 | // type CorePropsInter interface { 48 | // SetClass(string) 49 | // SetAttrs(templ.Attributes) 50 | // SetAttr(string, any) 51 | // Class() string 52 | // Attrs() templ.Attributes 53 | // } 54 | // 55 | // func (p *CoreProps) SetClass(c string) { 56 | // p.class = c 57 | // } 58 | // 59 | // func (p *CoreProps) SetAttrs(a templ.Attributes) { 60 | // p.attrs = a 61 | // } 62 | // 63 | // func (p *CoreProps) SetAttr(k string, v any) { 64 | // p.attrs[k] = v 65 | // } 66 | // 67 | // func (p *CoreProps) Class() string { 68 | // return p.class 69 | // } 70 | // 71 | // func (p *CoreProps) Attrs() templ.Attributes { 72 | // return p.attrs 73 | // } 74 | -------------------------------------------------------------------------------- /primitives/utils.go: -------------------------------------------------------------------------------- 1 | package primitives 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/a-h/templ" 8 | ) 9 | 10 | const ( 11 | propPrefix = "shadcntempl" 12 | ) 13 | 14 | // Id returns a string to be used with alpine's `:id` directive. 15 | // 16 | // example: 17 | // 18 | // 19 | // // :id="`${$id('label')}:header`" 20 | func Id(scope, postfix string) string { 21 | return fmt.Sprintf("`${$id('%s')}:%s`", scope, postfix) 22 | } 23 | 24 | // Scope returns a string to define an alpine id scope using the `x-id` directive. 25 | func Scope(name string) string { 26 | return fmt.Sprintf("['%s']", name) 27 | } 28 | 29 | type Data map[string]string 30 | 31 | func (d Data) String() string { 32 | var b strings.Builder 33 | b.WriteString("{ ") 34 | for k, v := range d { 35 | if k != "" && v != "" { 36 | b.WriteString(fmt.Sprintf("%s: %s, ", k, v)) 37 | } 38 | } 39 | b.WriteString("}") 40 | return b.String() 41 | } 42 | 43 | // Data builds a `x-data` directive from a map. 44 | // 45 | // example: 46 | // 47 | // Data({{ "state", "'open'" }}) 48 | // // "{ state: 'open', }" 49 | // func Data(kvs XData) string { 50 | // var b strings.Builder 51 | // b.WriteString("{ ") 52 | // for k, v := range kvs { 53 | // if k != "" && v != "" { 54 | // b.WriteString(fmt.Sprintf("%s: %s, ", k, v)) 55 | // } 56 | // } 57 | // b.WriteString("}") 58 | // return b.String() 59 | // } 60 | 61 | // Prop formats a string to be a shadcn-templ prop. 62 | // 63 | // example: 64 | // 65 | // x-data={ Data({{ Prop("open"), "false" }}) } 66 | // // x-data="{ shadcntempl_open: false, }" 67 | func Prop(p string) string { 68 | return fmt.Sprintf("%s_%s", propPrefix, p) 69 | } 70 | 71 | // ExtractClass takes the class attribute, returns it, and DELETES it. 72 | // If no class is defined, returns an empty string. 73 | func ExtractClass(attrs templ.Attributes) any { 74 | if class, ok := attrs["class"]; ok { 75 | delete(attrs, "class") 76 | return class 77 | } 78 | return "" 79 | } 80 | -------------------------------------------------------------------------------- /static/css/input.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --background: 0 0% 100%; 8 | --foreground: 240 10% 3.9%; 9 | --card: 0 0% 100%; 10 | --card-foreground: 240 10% 3.9%; 11 | --popover: 0 0% 100%; 12 | --popover-foreground: 240 10% 3.9%; 13 | --primary: 240 5.9% 10%; 14 | --primary-foreground: 0 0% 98%; 15 | --secondary: 240 4.8% 95.9%; 16 | --secondary-foreground: 240 5.9% 10%; 17 | --muted: 240 4.8% 95.9%; 18 | --muted-foreground: 240 3.8% 46.1%; 19 | --accent: 240 4.8% 95.9%; 20 | --accent-foreground: 240 5.9% 10%; 21 | --destructive: 0 72.22% 50.59%; 22 | --destructive-foreground: 0 0% 98%; 23 | --border: 240 5.9% 90%; 24 | --input: 240 5.9% 90%; 25 | --ring: 240 5.9% 10%; 26 | --radius: 0.5rem; 27 | } 28 | .dark { 29 | --background: 240 10% 3.9%; 30 | --foreground: 0 0% 98%; 31 | --card: 240 10% 3.9%; 32 | --card-foreground: 0 0% 98%; 33 | --popover: 240 10% 3.9%; 34 | --popover-foreground: 0 0% 98%; 35 | --primary: 0 0% 98%; 36 | --primary-foreground: 240 5.9% 10%; 37 | --secondary: 240 3.7% 15.9%; 38 | --secondary-foreground: 0 0% 98%; 39 | --muted: 240 3.7% 15.9%; 40 | --muted-foreground: 240 5% 64.9%; 41 | --accent: 240 3.7% 15.9%; 42 | --accent-foreground: 0 0% 98%; 43 | --destructive: 0 62.8% 30.6%; 44 | --destructive-foreground: 0 0% 98%; 45 | --border: 240 3.7% 15.9%; 46 | --input: 240 3.7% 15.9%; 47 | --ring: 240 4.9% 83.9%; 48 | } 49 | } 50 | 51 | @layer base { 52 | * { 53 | @apply border-border; 54 | } 55 | body { 56 | @apply bg-background text-foreground; 57 | font-feature-settings: "rlig" 1, "calt" 1; 58 | } 59 | } 60 | 61 | /* for Alpine.js */ 62 | [x-cloak] { 63 | display: none !important; 64 | } 65 | 66 | [aria-hidden="true"], 67 | [aria-hidden="true"] * { 68 | pointer-events: none; 69 | } 70 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | import { fontFamily } from "tailwindcss/defaultTheme"; 2 | 3 | /** @type {import('tailwindcss').Config} */ 4 | module.exports = { 5 | darkMode: ["selector"], 6 | content: [ "./**/*.html", "./**/*.templ", "./**/*.go", ], 7 | theme: { 8 | container: { 9 | center: true, 10 | padding: "2rem", 11 | screens: { 12 | "2xl": "1400px", 13 | }, 14 | }, 15 | extend: { 16 | colors: { 17 | border: "hsl(var(--border))", 18 | input: "hsl(var(--input))", 19 | ring: "hsl(var(--ring))", 20 | background: "hsl(var(--background))", 21 | foreground: "hsl(var(--foreground))", 22 | primary: { 23 | DEFAULT: "hsl(var(--primary))", 24 | foreground: "hsl(var(--primary-foreground))", 25 | }, 26 | secondary: { 27 | DEFAULT: "hsl(var(--secondary))", 28 | foreground: "hsl(var(--secondary-foreground))", 29 | }, 30 | destructive: { 31 | DEFAULT: "hsl(var(--destructive))", 32 | foreground: "hsl(var(--destructive-foreground))", 33 | }, 34 | muted: { 35 | DEFAULT: "hsl(var(--muted))", 36 | foreground: "hsl(var(--muted-foreground))", 37 | }, 38 | accent: { 39 | DEFAULT: "hsl(var(--accent))", 40 | foreground: "hsl(var(--accent-foreground))", 41 | }, 42 | popover: { 43 | DEFAULT: "hsl(var(--popover))", 44 | foreground: "hsl(var(--popover-foreground))", 45 | }, 46 | card: { 47 | DEFAULT: "hsl(var(--card))", 48 | foreground: "hsl(var(--card-foreground))", 49 | }, 50 | }, 51 | borderRadius: { 52 | lg: `var(--radius)`, 53 | md: `calc(var(--radius) - 2px)`, 54 | sm: "calc(var(--radius) - 4px)", 55 | }, 56 | fontFamily: { 57 | sans: ["Inter", ...fontFamily.sans], 58 | }, 59 | }, 60 | }, 61 | plugins: [ 62 | require("./tailwindcss-animate"), 63 | ], 64 | } 65 | 66 | -------------------------------------------------------------------------------- /tailwindcss-animate.js: -------------------------------------------------------------------------------- 1 | /* 2 | * tailwindcss-animate source. 3 | * 4 | * https://github.com/jamiebuilds/tailwindcss-animate/blob/main/index.js 5 | */ 6 | 7 | const plugin = require("tailwindcss/plugin") 8 | 9 | function filterDefault(values) { 10 | return Object.fromEntries( 11 | Object.entries(values).filter(([key]) => key !== "DEFAULT"), 12 | ) 13 | } 14 | 15 | module.exports = plugin( 16 | ({ addUtilities, matchUtilities, theme }) => { 17 | addUtilities({ 18 | "@keyframes enter": theme("keyframes.enter"), 19 | "@keyframes exit": theme("keyframes.exit"), 20 | ".animate-in": { 21 | animationName: "enter", 22 | animationDuration: theme("animationDuration.DEFAULT"), 23 | "--tw-enter-opacity": "initial", 24 | "--tw-enter-scale": "initial", 25 | "--tw-enter-rotate": "initial", 26 | "--tw-enter-translate-x": "initial", 27 | "--tw-enter-translate-y": "initial", 28 | }, 29 | ".animate-out": { 30 | animationName: "exit", 31 | animationDuration: theme("animationDuration.DEFAULT"), 32 | "--tw-exit-opacity": "initial", 33 | "--tw-exit-scale": "initial", 34 | "--tw-exit-rotate": "initial", 35 | "--tw-exit-translate-x": "initial", 36 | "--tw-exit-translate-y": "initial", 37 | }, 38 | }) 39 | 40 | matchUtilities( 41 | { 42 | "fade-in": (value) => ({ "--tw-enter-opacity": value }), 43 | "fade-out": (value) => ({ "--tw-exit-opacity": value }), 44 | }, 45 | { values: theme("animationOpacity") }, 46 | ) 47 | 48 | matchUtilities( 49 | { 50 | "zoom-in": (value) => ({ "--tw-enter-scale": value }), 51 | "zoom-out": (value) => ({ "--tw-exit-scale": value }), 52 | }, 53 | { values: theme("animationScale") }, 54 | ) 55 | 56 | matchUtilities( 57 | { 58 | "spin-in": (value) => ({ "--tw-enter-rotate": value }), 59 | "spin-out": (value) => ({ "--tw-exit-rotate": value }), 60 | }, 61 | { values: theme("animationRotate") }, 62 | ) 63 | 64 | matchUtilities( 65 | { 66 | "slide-in-from-top": (value) => ({ 67 | "--tw-enter-translate-y": `-${value}`, 68 | }), 69 | "slide-in-from-bottom": (value) => ({ 70 | "--tw-enter-translate-y": value, 71 | }), 72 | "slide-in-from-left": (value) => ({ 73 | "--tw-enter-translate-x": `-${value}`, 74 | }), 75 | "slide-in-from-right": (value) => ({ 76 | "--tw-enter-translate-x": value, 77 | }), 78 | "slide-out-to-top": (value) => ({ 79 | "--tw-exit-translate-y": `-${value}`, 80 | }), 81 | "slide-out-to-bottom": (value) => ({ 82 | "--tw-exit-translate-y": value, 83 | }), 84 | "slide-out-to-left": (value) => ({ 85 | "--tw-exit-translate-x": `-${value}`, 86 | }), 87 | "slide-out-to-right": (value) => ({ 88 | "--tw-exit-translate-x": value, 89 | }), 90 | }, 91 | { values: theme("animationTranslate") }, 92 | ) 93 | 94 | matchUtilities( 95 | { duration: (value) => ({ animationDuration: value }) }, 96 | { values: filterDefault(theme("animationDuration")) }, 97 | ) 98 | 99 | matchUtilities( 100 | { delay: (value) => ({ animationDelay: value }) }, 101 | { values: theme("animationDelay") }, 102 | ) 103 | 104 | matchUtilities( 105 | { ease: (value) => ({ animationTimingFunction: value }) }, 106 | { values: filterDefault(theme("animationTimingFunction")) }, 107 | ) 108 | 109 | addUtilities({ 110 | ".running": { animationPlayState: "running" }, 111 | ".paused": { animationPlayState: "paused" }, 112 | }) 113 | 114 | matchUtilities( 115 | { "fill-mode": (value) => ({ animationFillMode: value }) }, 116 | { values: theme("animationFillMode") }, 117 | ) 118 | 119 | matchUtilities( 120 | { direction: (value) => ({ animationDirection: value }) }, 121 | { values: theme("animationDirection") }, 122 | ) 123 | 124 | matchUtilities( 125 | { repeat: (value) => ({ animationIterationCount: value }) }, 126 | { values: theme("animationRepeat") }, 127 | ) 128 | }, 129 | { 130 | theme: { 131 | extend: { 132 | animationDelay: ({ theme }) => ({ 133 | ...theme("transitionDelay"), 134 | }), 135 | animationDuration: ({ theme }) => ({ 136 | 0: "0ms", 137 | ...theme("transitionDuration"), 138 | }), 139 | animationTimingFunction: ({ theme }) => ({ 140 | ...theme("transitionTimingFunction"), 141 | }), 142 | animationFillMode: { 143 | none: "none", 144 | forwards: "forwards", 145 | backwards: "backwards", 146 | both: "both", 147 | }, 148 | animationDirection: { 149 | normal: "normal", 150 | reverse: "reverse", 151 | alternate: "alternate", 152 | "alternate-reverse": "alternate-reverse", 153 | }, 154 | animationOpacity: ({ theme }) => ({ 155 | DEFAULT: 0, 156 | ...theme("opacity"), 157 | }), 158 | animationTranslate: ({ theme }) => ({ 159 | DEFAULT: "100%", 160 | ...theme("translate"), 161 | }), 162 | animationScale: ({ theme }) => ({ 163 | DEFAULT: 0, 164 | ...theme("scale"), 165 | }), 166 | animationRotate: ({ theme }) => ({ 167 | DEFAULT: "30deg", 168 | ...theme("rotate"), 169 | }), 170 | animationRepeat: { 171 | 0: "0", 172 | 1: "1", 173 | infinite: "infinite", 174 | }, 175 | keyframes: { 176 | enter: { 177 | from: { 178 | opacity: "var(--tw-enter-opacity, 1)", 179 | transform: 180 | "translate3d(var(--tw-enter-translate-x, 0), var(--tw-enter-translate-y, 0), 0) scale3d(var(--tw-enter-scale, 1), var(--tw-enter-scale, 1), var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0))", 181 | }, 182 | }, 183 | exit: { 184 | to: { 185 | opacity: "var(--tw-exit-opacity, 1)", 186 | transform: 187 | "translate3d(var(--tw-exit-translate-x, 0), var(--tw-exit-translate-y, 0), 0) scale3d(var(--tw-exit-scale, 1), var(--tw-exit-scale, 1), var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0))", 188 | }, 189 | }, 190 | }, 191 | }, 192 | }, 193 | }, 194 | ) 195 | -------------------------------------------------------------------------------- /ui/accordion.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import ( 4 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 5 | "github.com/rotemhoresh/shadcn-templ/icons" 6 | ) 7 | 8 | const ( 9 | accordionBaseClass = "w-full" 10 | accordionItemBaseClass = "border-b" 11 | accordionTriggerBaseClass = "flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline" 12 | accordionContentBaseClass = "overflow-hidden text-sm" 13 | ) 14 | 15 | templ Accordion(classes string, attrs templ.Attributes) { 16 |
21 | { children... } 22 |
23 | } 24 | 25 | templ AccordionItem(classes string, attrs templ.Attributes) { 26 |
31 | { children... } 32 |
33 | } 34 | 35 | templ AccordionTrigger(classes string, attrs templ.Attributes) { 36 |

37 | 48 |

49 | } 50 | 51 | templ AccorionContent(classes string, attrs templ.Attributes) { 52 |
59 |
62 | { children... } 63 |
64 |
65 | } 66 | -------------------------------------------------------------------------------- /ui/alert.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import ( 4 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 5 | "github.com/rotemhoresh/shadcn-templ/icons" 6 | ) 7 | 8 | const ( 9 | alertBaseClass = "[&>svg]:text-foreground relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg~*]:pl-7" 10 | alertTitleBaseClass = "mb-1 font-medium leading-none tracking-tight" 11 | alertDescriptionBaseClass = "text-sm [&_p]:leading-relaxed" 12 | ) 13 | 14 | type AlertVariant int 15 | 16 | const ( 17 | AlertVariantDefault AlertVariant = iota 18 | AlertVariantDestructive 19 | ) 20 | 21 | func (v AlertVariant) Class() string { 22 | switch v { 23 | case AlertVariantDestructive: 24 | return "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive" 25 | default: 26 | return "bg-background text-foreground" 27 | } 28 | } 29 | 30 | func (v AlertVariant) Icon() templ.Component { 31 | switch v { 32 | case AlertVariantDestructive: 33 | return icons.CircleX(icons.Props{ 34 | Class: "h-4 w-4", 35 | }) 36 | default: 37 | return icons.CircleCheck(icons.Props{ 38 | Class: "h-4 w-4", 39 | }) 40 | } 41 | } 42 | 43 | templ Alert(variant AlertVariant, classes string, attrs templ.Attributes) { 44 | 52 | } 53 | 54 | templ AlertTitle(classes string, attrs templ.Attributes) { 55 |
59 | { children... } 60 |
61 | } 62 | 63 | templ AlertDescription(classes string, attrs templ.Attributes) { 64 |
68 | { children... } 69 |
70 | } 71 | -------------------------------------------------------------------------------- /ui/aspect-ratio/generated_optaliase.go: -------------------------------------------------------------------------------- 1 | // Code generated by "optaliase_generator.go -type=RootProps"; DO NOT EDIT. 2 | 3 | package aspectratio 4 | 5 | import "github.com/rotemhoresh/shadcn-templ/ui" 6 | 7 | var ( 8 | WithClass = ui.WithClass[*RootProps] 9 | WithAttrs = ui.WithAttrs[*RootProps] 10 | WithAttr = ui.WithAttr[*RootProps] 11 | ) 12 | -------------------------------------------------------------------------------- /ui/aspect-ratio/root.templ: -------------------------------------------------------------------------------- 1 | package aspectratio 2 | 3 | import ( 4 | "fmt" 5 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 6 | "github.com/rotemhoresh/shadcn-templ/ui" 7 | ) 8 | 9 | type RootProps struct { 10 | ratio float32 11 | ui.CoreProps 12 | } 13 | 14 | type RootOption = ui.Option[*RootProps] 15 | 16 | // note that `16/9` will result in `1`. you need to convert one of the numbers to float, e.g., `16.0/9.0`. 17 | func WithRatio(r float32) RootOption { 18 | return func(p *RootProps) { 19 | p.ratio = r 20 | } 21 | } 22 | 23 | //go:generate go run ../optalias_generator.go -type=RootProps 24 | 25 | func Root(opts ...RootOption) templ.Component { 26 | p := &RootProps{ 27 | ratio: 1 / 1, 28 | CoreProps: ui.DefaultCoreProps, 29 | } 30 | for _, opt := range opts { 31 | opt(p) 32 | } 33 | return root(p) 34 | } 35 | 36 | css rootStyle() { 37 | position: absolute; 38 | top: 0; 39 | right: 0; 40 | bottom: 0; 41 | left: 0; 42 | } 43 | 44 | css rootWrapperStyle(r float32) { 45 | position: relative; 46 | width: 100%; 47 | padding-bottom: { fmt.Sprintf("%.2f%%", 100/r) }; 48 | } 49 | 50 | templ root(props *RootProps) { 51 |
54 |
58 | { children... } 59 |
60 |
61 | } 62 | -------------------------------------------------------------------------------- /ui/aspect-ratio/root_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package aspectratio 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | "fmt" 13 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 14 | "github.com/rotemhoresh/shadcn-templ/ui" 15 | ) 16 | 17 | type RootProps struct { 18 | ratio float32 19 | ui.CoreProps 20 | } 21 | 22 | type RootOption = ui.Option[*RootProps] 23 | 24 | // note that `16/9` will result in `1`. you need to convert one of the numbers to float, e.g., `16.0/9.0`. 25 | func WithRatio(r float32) RootOption { 26 | return func(p *RootProps) { 27 | p.ratio = r 28 | } 29 | } 30 | 31 | //go:generate go run ../optalias_generator.go -type=RootProps 32 | 33 | func Root(opts ...RootOption) templ.Component { 34 | p := &RootProps{ 35 | ratio: 1 / 1, 36 | CoreProps: ui.DefaultCoreProps, 37 | } 38 | for _, opt := range opts { 39 | opt(p) 40 | } 41 | return root(p) 42 | } 43 | 44 | func rootStyle() templ.CSSClass { 45 | templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() 46 | templ_7745c5c3_CSSBuilder.WriteString(`position:absolute;`) 47 | templ_7745c5c3_CSSBuilder.WriteString(`top:0;`) 48 | templ_7745c5c3_CSSBuilder.WriteString(`right:0;`) 49 | templ_7745c5c3_CSSBuilder.WriteString(`bottom:0;`) 50 | templ_7745c5c3_CSSBuilder.WriteString(`left:0;`) 51 | templ_7745c5c3_CSSID := templ.CSSID(`rootStyle`, templ_7745c5c3_CSSBuilder.String()) 52 | return templ.ComponentCSSClass{ 53 | ID: templ_7745c5c3_CSSID, 54 | Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), 55 | } 56 | } 57 | 58 | func rootWrapperStyle(r float32) templ.CSSClass { 59 | templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() 60 | templ_7745c5c3_CSSBuilder.WriteString(`position:relative;`) 61 | templ_7745c5c3_CSSBuilder.WriteString(`width:100%;`) 62 | templ_7745c5c3_CSSBuilder.WriteString(string(templ.SanitizeCSS(`padding-bottom`, fmt.Sprintf("%.2f%%", 100/r)))) 63 | templ_7745c5c3_CSSID := templ.CSSID(`rootWrapperStyle`, templ_7745c5c3_CSSBuilder.String()) 64 | return templ.ComponentCSSClass{ 65 | ID: templ_7745c5c3_CSSID, 66 | Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), 67 | } 68 | } 69 | 70 | func root(props *RootProps) templ.Component { 71 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 72 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 73 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 74 | return templ_7745c5c3_CtxErr 75 | } 76 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 77 | if !templ_7745c5c3_IsBuffer { 78 | defer func() { 79 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 80 | if templ_7745c5c3_Err == nil { 81 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 82 | } 83 | }() 84 | } 85 | ctx = templ.InitializeContext(ctx) 86 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 87 | if templ_7745c5c3_Var1 == nil { 88 | templ_7745c5c3_Var1 = templ.NopComponent 89 | } 90 | ctx = templ.ClearChildren(ctx) 91 | var templ_7745c5c3_Var2 = []any{rootWrapperStyle(props.ratio)} 92 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 93 | if templ_7745c5c3_Err != nil { 94 | return templ_7745c5c3_Err 95 | } 96 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 110 | if templ_7745c5c3_Err != nil { 111 | return templ_7745c5c3_Err 112 | } 113 | var templ_7745c5c3_Var4 = []any{rootStyle(), twmerge.Merge(props.Class())} 114 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var4...) 115 | if templ_7745c5c3_Err != nil { 116 | return templ_7745c5c3_Err 117 | } 118 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 140 | if templ_7745c5c3_Err != nil { 141 | return templ_7745c5c3_Err 142 | } 143 | templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) 144 | if templ_7745c5c3_Err != nil { 145 | return templ_7745c5c3_Err 146 | } 147 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 148 | if templ_7745c5c3_Err != nil { 149 | return templ_7745c5c3_Err 150 | } 151 | return templ_7745c5c3_Err 152 | }) 153 | } 154 | 155 | var _ = templruntime.GeneratedTemplate 156 | -------------------------------------------------------------------------------- /ui/avatar.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import ( 4 | "fmt" 5 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 6 | ) 7 | 8 | const ( 9 | avatarBaseClass = "relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full" 10 | avatarImageBaseClass = "aspect-square h-full w-full" 11 | avatarFallbackBaseClass = "flex h-full w-full items-center justify-center rounded-full bg-muted" 12 | ) 13 | 14 | templ Avatar(classes string, attrs templ.Attributes) { 15 | 20 | { children... } 21 | 22 | } 23 | 24 | templ AvatarImage(src, alt, classes string, attrs templ.Attributes) { 25 | status = 'loaded'; 35 | this.image.onerror = () => status = 'error'; 36 | this.image.src = '%s'; 37 | } 38 | }`, src) } 39 | src={ src } 40 | alt={ alt } 41 | class={ twmerge.Merge(avatarBaseClass, classes) } 42 | { attrs... } 43 | x-cloak 44 | x-show="status === 'loaded'" 45 | /> 46 | } 47 | 48 | templ AvatarFallback(classes string, attrs templ.Attributes) { 49 | 55 | { children... } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /ui/badge.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 4 | 5 | const ( 6 | BadgeBaseClass = "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2" 7 | ) 8 | 9 | type BadgeVariant int 10 | 11 | const ( 12 | BadgeVariantDefault = iota 13 | BadgeVariantSecondary 14 | BadgeVariantDestructive 15 | BadgeVariantOutline 16 | ) 17 | 18 | func (v BadgeVariant) Class() string { 19 | switch v { 20 | case BadgeVariantSecondary: 21 | return "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80" 22 | case BadgeVariantDestructive: 23 | return "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80" 24 | case BadgeVariantOutline: 25 | return "text-foreground" 26 | default: 27 | return "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80" 28 | } 29 | } 30 | 31 | templ Badge(variant BadgeVariant, classes string, attrs templ.Attributes) { 32 |
36 | { children... } 37 |
38 | } 39 | -------------------------------------------------------------------------------- /ui/badge_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package ui 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 12 | 13 | const ( 14 | BadgeBaseClass = "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2" 15 | ) 16 | 17 | type BadgeVariant int 18 | 19 | const ( 20 | BadgeVariantDefault = iota 21 | BadgeVariantSecondary 22 | BadgeVariantDestructive 23 | BadgeVariantOutline 24 | ) 25 | 26 | func (v BadgeVariant) Class() string { 27 | switch v { 28 | case BadgeVariantSecondary: 29 | return "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80" 30 | case BadgeVariantDestructive: 31 | return "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80" 32 | case BadgeVariantOutline: 33 | return "text-foreground" 34 | default: 35 | return "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80" 36 | } 37 | } 38 | 39 | func Badge(variant BadgeVariant, classes string, attrs templ.Attributes) templ.Component { 40 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 41 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 42 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 43 | return templ_7745c5c3_CtxErr 44 | } 45 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 46 | if !templ_7745c5c3_IsBuffer { 47 | defer func() { 48 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 49 | if templ_7745c5c3_Err == nil { 50 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 51 | } 52 | }() 53 | } 54 | ctx = templ.InitializeContext(ctx) 55 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 56 | if templ_7745c5c3_Var1 == nil { 57 | templ_7745c5c3_Var1 = templ.NopComponent 58 | } 59 | ctx = templ.ClearChildren(ctx) 60 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(BadgeBaseClass, variant.Class(), classes)} 61 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 62 | if templ_7745c5c3_Err != nil { 63 | return templ_7745c5c3_Err 64 | } 65 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 87 | if templ_7745c5c3_Err != nil { 88 | return templ_7745c5c3_Err 89 | } 90 | templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) 91 | if templ_7745c5c3_Err != nil { 92 | return templ_7745c5c3_Err 93 | } 94 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 95 | if templ_7745c5c3_Err != nil { 96 | return templ_7745c5c3_Err 97 | } 98 | return templ_7745c5c3_Err 99 | }) 100 | } 101 | 102 | var _ = templruntime.GeneratedTemplate 103 | -------------------------------------------------------------------------------- /ui/breadcrumb.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import ( 4 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 5 | "github.com/rotemhoresh/shadcn-templ/icons" 6 | ) 7 | 8 | const ( 9 | breadcrumbListBaseClass = "flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5" 10 | breadcrumbItemBaseClass = "inline-flex items-center gap-1.5" 11 | breadcrumbSeparatorBaseClass = "[&>svg]:size-3.5" 12 | breadcrumbLinkBaseClass = "transition-colors hover:text-foreground" 13 | ) 14 | 15 | templ Breadcrumb(classes string, attrs templ.Attributes) { 16 | 23 | } 24 | 25 | templ BreadcrumbList(classes string, attrs templ.Attributes) { 26 |
    30 | { children... } 31 |
32 | } 33 | 34 | templ BreadcrumbItem(classes string, attrs templ.Attributes) { 35 |
  • 39 | { children... } 40 |
  • 41 | } 42 | 43 | templ BreadcrumbSeparator(classes string, attrs templ.Attributes) { 44 | 54 | } 55 | 56 | templ BreadcrumbLink(href templ.SafeURL, classes string, attrs templ.Attributes) { 57 | 62 | { children... } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /ui/button.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 4 | 5 | const buttonBaseClass = "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" 6 | 7 | type ButtonType int 8 | 9 | const ( 10 | ButtonTypeButton ButtonType = iota 11 | ButtonTypeSubmit 12 | ButtonTypeReset 13 | ) 14 | 15 | func (t ButtonType) String() string { 16 | switch t { 17 | case ButtonTypeSubmit: 18 | return "submit" 19 | case ButtonTypeReset: 20 | return "reset" 21 | default: 22 | return "button" 23 | } 24 | } 25 | 26 | type ButtonVariant int 27 | 28 | const ( 29 | ButtonVariantDefault ButtonVariant = iota 30 | ButtonVariantDestructive 31 | ButtonVariantSecondary 32 | ButtonVariantOutline 33 | ButtonVariantGhost 34 | ButtonVariantLink 35 | ) 36 | 37 | func (v ButtonVariant) Class() string { 38 | switch v { 39 | case ButtonVariantDestructive: 40 | return "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90" 41 | case ButtonVariantSecondary: 42 | return "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80" 43 | case ButtonVariantOutline: 44 | return "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground" 45 | case ButtonVariantGhost: 46 | return "hover:bg-accent hover:text-accent-foreground" 47 | case ButtonVariantLink: 48 | return "text-primary underline-offset-4 hover:underline" 49 | default: 50 | return "bg-primary text-primary-foreground shadow hover:bg-primary/90" 51 | } 52 | } 53 | 54 | type ButtonSize int 55 | 56 | const ( 57 | ButtonSizeDefault ButtonSize = iota 58 | ButtonSizeSmall 59 | ButtonSizeLarge 60 | ButtonSizeIcon 61 | ) 62 | 63 | func (s ButtonSize) Class() string { 64 | switch s { 65 | case ButtonSizeSmall: 66 | return "h-8 rounded-md px-3 text-xs" 67 | case ButtonSizeLarge: 68 | return "h-10 rounded-md px-8" 69 | case ButtonSizeIcon: 70 | return "h-9 w-9" 71 | default: 72 | return "h-9 px-4 py-2" 73 | } 74 | } 75 | 76 | templ Button(buttonType ButtonType, variant ButtonVariant, size ButtonSize, classes string, attrs templ.Attributes) { 77 | 84 | } 85 | -------------------------------------------------------------------------------- /ui/button/root.templ: -------------------------------------------------------------------------------- 1 | package button 2 | 3 | import ( 4 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 5 | p "github.com/rotemhoresh/shadcn-templ/primitives" 6 | ) 7 | 8 | const baseClass = "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" 9 | 10 | type Type int 11 | 12 | const ( 13 | TypeButton Type = iota 14 | TypeSubmit 15 | TypeReset 16 | ) 17 | 18 | func (t Type) String() string { 19 | switch t { 20 | case TypeSubmit: 21 | return "submit" 22 | case TypeReset: 23 | return "reset" 24 | default: 25 | return "button" 26 | } 27 | } 28 | 29 | type Variant int 30 | 31 | const ( 32 | VariantDefault Variant = iota 33 | VariantDestructive 34 | VariantSecondary 35 | VariantOutline 36 | VariantGhost 37 | VariantLink 38 | ) 39 | 40 | func (v Variant) Class() string { 41 | switch v { 42 | case VariantDestructive: 43 | return "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90" 44 | case VariantSecondary: 45 | return "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80" 46 | case VariantOutline: 47 | return "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground" 48 | case VariantGhost: 49 | return "hover:bg-accent hover:text-accent-foreground" 50 | case VariantLink: 51 | return "text-primary underline-offset-4 hover:underline" 52 | default: 53 | return "bg-primary text-primary-foreground shadow hover:bg-primary/90" 54 | } 55 | } 56 | 57 | type Size int 58 | 59 | const ( 60 | SizeDefault Size = iota 61 | SizeSmall 62 | SizeLarge 63 | SizeIcon 64 | ) 65 | 66 | func (s Size) Class() string { 67 | switch s { 68 | case SizeSmall: 69 | return "h-8 rounded-md px-3 text-xs" 70 | case SizeLarge: 71 | return "h-10 rounded-md px-8" 72 | case SizeIcon: 73 | return "h-9 w-9" 74 | default: 75 | return "h-9 px-4 py-2" 76 | } 77 | } 78 | 79 | type RootProps struct { 80 | Type Type // default: [TypeButton] 81 | Variant Variant // default: [VariantDefault] 82 | Size Size // default: [SizeDefault] 83 | p.CoreProps 84 | } 85 | 86 | var props = RootProps{} 87 | 88 | templ Root(content string /* props RootProps */) { 89 | 97 | } 98 | -------------------------------------------------------------------------------- /ui/button/root_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package button 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 13 | p "github.com/rotemhoresh/shadcn-templ/primitives" 14 | ) 15 | 16 | const baseClass = "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" 17 | 18 | type Type int 19 | 20 | const ( 21 | TypeButton Type = iota 22 | TypeSubmit 23 | TypeReset 24 | ) 25 | 26 | func (t Type) String() string { 27 | switch t { 28 | case TypeSubmit: 29 | return "submit" 30 | case TypeReset: 31 | return "reset" 32 | default: 33 | return "button" 34 | } 35 | } 36 | 37 | type Variant int 38 | 39 | const ( 40 | VariantDefault Variant = iota 41 | VariantDestructive 42 | VariantSecondary 43 | VariantOutline 44 | VariantGhost 45 | VariantLink 46 | ) 47 | 48 | func (v Variant) Class() string { 49 | switch v { 50 | case VariantDestructive: 51 | return "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90" 52 | case VariantSecondary: 53 | return "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80" 54 | case VariantOutline: 55 | return "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground" 56 | case VariantGhost: 57 | return "hover:bg-accent hover:text-accent-foreground" 58 | case VariantLink: 59 | return "text-primary underline-offset-4 hover:underline" 60 | default: 61 | return "bg-primary text-primary-foreground shadow hover:bg-primary/90" 62 | } 63 | } 64 | 65 | type Size int 66 | 67 | const ( 68 | SizeDefault Size = iota 69 | SizeSmall 70 | SizeLarge 71 | SizeIcon 72 | ) 73 | 74 | func (s Size) Class() string { 75 | switch s { 76 | case SizeSmall: 77 | return "h-8 rounded-md px-3 text-xs" 78 | case SizeLarge: 79 | return "h-10 rounded-md px-8" 80 | case SizeIcon: 81 | return "h-9 w-9" 82 | default: 83 | return "h-9 px-4 py-2" 84 | } 85 | } 86 | 87 | type RootProps struct { 88 | Type Type // default: [TypeButton] 89 | Variant Variant // default: [VariantDefault] 90 | Size Size // default: [SizeDefault] 91 | p.CoreProps 92 | } 93 | 94 | var props = RootProps{} 95 | 96 | func Root( /* props RootProps */ ) templ.Component { 97 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 98 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 99 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 100 | return templ_7745c5c3_CtxErr 101 | } 102 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 103 | if !templ_7745c5c3_IsBuffer { 104 | defer func() { 105 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 106 | if templ_7745c5c3_Err == nil { 107 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 108 | } 109 | }() 110 | } 111 | ctx = templ.InitializeContext(ctx) 112 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 113 | if templ_7745c5c3_Var1 == nil { 114 | templ_7745c5c3_Var1 = templ.NopComponent 115 | } 116 | ctx = templ.ClearChildren(ctx) 117 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(baseClass, props.Variant.Class(), props.Size.Class(), props.Class)} 118 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 119 | if templ_7745c5c3_Err != nil { 120 | return templ_7745c5c3_Err 121 | } 122 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 165 | if templ_7745c5c3_Err != nil { 166 | return templ_7745c5c3_Err 167 | } 168 | return templ_7745c5c3_Err 169 | }) 170 | } 171 | 172 | var _ = templruntime.GeneratedTemplate 173 | -------------------------------------------------------------------------------- /ui/button_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package ui 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 12 | 13 | const buttonBaseClass = "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" 14 | 15 | type ButtonType int 16 | 17 | const ( 18 | ButtonTypeButton ButtonType = iota 19 | ButtonTypeSubmit 20 | ButtonTypeReset 21 | ) 22 | 23 | func (t ButtonType) String() string { 24 | switch t { 25 | case ButtonTypeSubmit: 26 | return "submit" 27 | case ButtonTypeReset: 28 | return "reset" 29 | default: 30 | return "button" 31 | } 32 | } 33 | 34 | type ButtonVariant int 35 | 36 | const ( 37 | ButtonVariantDefault ButtonVariant = iota 38 | ButtonVariantDestructive 39 | ButtonVariantSecondary 40 | ButtonVariantOutline 41 | ButtonVariantGhost 42 | ButtonVariantLink 43 | ) 44 | 45 | func (v ButtonVariant) Class() string { 46 | switch v { 47 | case ButtonVariantDestructive: 48 | return "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90" 49 | case ButtonVariantSecondary: 50 | return "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80" 51 | case ButtonVariantOutline: 52 | return "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground" 53 | case ButtonVariantGhost: 54 | return "hover:bg-accent hover:text-accent-foreground" 55 | case ButtonVariantLink: 56 | return "text-primary underline-offset-4 hover:underline" 57 | default: 58 | return "bg-primary text-primary-foreground shadow hover:bg-primary/90" 59 | } 60 | } 61 | 62 | type ButtonSize int 63 | 64 | const ( 65 | ButtonSizeDefault ButtonSize = iota 66 | ButtonSizeSmall 67 | ButtonSizeLarge 68 | ButtonSizeIcon 69 | ) 70 | 71 | func (s ButtonSize) Class() string { 72 | switch s { 73 | case ButtonSizeSmall: 74 | return "h-8 rounded-md px-3 text-xs" 75 | case ButtonSizeLarge: 76 | return "h-10 rounded-md px-8" 77 | case ButtonSizeIcon: 78 | return "h-9 w-9" 79 | default: 80 | return "h-9 px-4 py-2" 81 | } 82 | } 83 | 84 | func Button(buttonType ButtonType, variant ButtonVariant, size ButtonSize, classes string, attrs templ.Attributes) templ.Component { 85 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 86 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 87 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 88 | return templ_7745c5c3_CtxErr 89 | } 90 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 91 | if !templ_7745c5c3_IsBuffer { 92 | defer func() { 93 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 94 | if templ_7745c5c3_Err == nil { 95 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 96 | } 97 | }() 98 | } 99 | ctx = templ.InitializeContext(ctx) 100 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 101 | if templ_7745c5c3_Var1 == nil { 102 | templ_7745c5c3_Var1 = templ.NopComponent 103 | } 104 | ctx = templ.ClearChildren(ctx) 105 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(buttonBaseClass, variant.Class(), size.Class(), classes)} 106 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 107 | if templ_7745c5c3_Err != nil { 108 | return templ_7745c5c3_Err 109 | } 110 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 153 | if templ_7745c5c3_Err != nil { 154 | return templ_7745c5c3_Err 155 | } 156 | return templ_7745c5c3_Err 157 | }) 158 | } 159 | 160 | var _ = templruntime.GeneratedTemplate 161 | -------------------------------------------------------------------------------- /ui/card.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import "github.com/Oudwins/tailwind-merge-go" 4 | 5 | const ( 6 | cardBaseClass = "rounded-xl border bg-card text-card-foreground shadow" 7 | cardHeaderBaseClass = "flex flex-col space-y-1.5 p-6" 8 | cardTitleBaseClass = "font-semibold leading-none tracking-tight" 9 | cardDescriptionBaseClass = "text-sm text-muted-foreground" 10 | cardContentBaseClass = "p-6 pt-0" 11 | cardFooterBaseClass = "flex items-center p-6 pt-0" 12 | ) 13 | 14 | templ Card(classes string, attrs templ.Attributes) { 15 |
    19 | { children... } 20 |
    21 | } 22 | 23 | templ CardHeader(classes string, attrs templ.Attributes) { 24 |
    28 | { children... } 29 |
    30 | } 31 | 32 | templ CardTitle(classes string, attrs templ.Attributes) { 33 |

    37 | { children... } 38 |

    39 | } 40 | 41 | templ CardDescription(classes string, attrs templ.Attributes) { 42 |

    46 | { children... } 47 |

    48 | } 49 | 50 | templ CardContent(classes string, attrs templ.Attributes) { 51 |
    55 | { children... } 56 |
    57 | } 58 | 59 | templ CardFooter(classes string, attrs templ.Attributes) { 60 |
    64 | { children... } 65 |
    66 | } -------------------------------------------------------------------------------- /ui/checkbox.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import ( 4 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 5 | "github.com/rotemhoresh/shadcn-templ/icons" 6 | ) 7 | 8 | const ( 9 | checkboxBaseClass = "peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground" 10 | ) 11 | 12 | // `attrs` will go to the inner input 13 | templ Checkbox(name, classes string, attrs templ.Attributes) { 14 | 54 | } 55 | -------------------------------------------------------------------------------- /ui/checkbox_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package ui 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 13 | "github.com/rotemhoresh/shadcn-templ/icons" 14 | ) 15 | 16 | const ( 17 | checkboxBaseClass = "peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground" 18 | ) 19 | 20 | // `attrs` will go to the inner input 21 | func Checkbox(name, classes string, attrs templ.Attributes) templ.Component { 22 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 23 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 24 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 25 | return templ_7745c5c3_CtxErr 26 | } 27 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 28 | if !templ_7745c5c3_IsBuffer { 29 | defer func() { 30 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 31 | if templ_7745c5c3_Err == nil { 32 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 33 | } 34 | }() 35 | } 36 | ctx = templ.InitializeContext(ctx) 37 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 38 | if templ_7745c5c3_Var1 == nil { 39 | templ_7745c5c3_Var1 = templ.NopComponent 40 | } 41 | ctx = templ.ClearChildren(ctx) 42 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(checkboxBaseClass, classes)} 43 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 44 | if templ_7745c5c3_Err != nil { 45 | return templ_7745c5c3_Err 46 | } 47 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 122 | if templ_7745c5c3_Err != nil { 123 | return templ_7745c5c3_Err 124 | } 125 | return templ_7745c5c3_Err 126 | }) 127 | } 128 | 129 | var _ = templruntime.GeneratedTemplate 130 | -------------------------------------------------------------------------------- /ui/collapsible.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import ( 4 | "fmt" 5 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 6 | ) 7 | 8 | templ Collapsible(defaultOpen bool, classes string, attrs templ.Attributes) { 9 |
    16 | { children... } 17 |
    18 | } 19 | 20 | // There is no element for collapsible trigger, just add these attributes to your component. 21 | var CollapsibleTriggerAttrs = templ.Attributes{ 22 | "x-data": true, 23 | "x-on:click": "shadcntempl_open = ! shadcntempl_open", 24 | ":aria-expanded": "shadcntempl_open", 25 | ":data-state": "shadcntempl_open ? 'open' : 'closed'", 26 | ":data-disabled": "shadcntempl_disabled", 27 | } 28 | 29 | templ CollapsibleContent(classes string, attrs templ.Attributes) { 30 |
    38 | { children... } 39 |
    40 | } 41 | -------------------------------------------------------------------------------- /ui/collapsible_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package ui 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | "fmt" 13 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 14 | ) 15 | 16 | func Collapsible(defaultOpen bool, classes string, attrs templ.Attributes) templ.Component { 17 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 18 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 19 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 20 | return templ_7745c5c3_CtxErr 21 | } 22 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 23 | if !templ_7745c5c3_IsBuffer { 24 | defer func() { 25 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 26 | if templ_7745c5c3_Err == nil { 27 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 28 | } 29 | }() 30 | } 31 | ctx = templ.InitializeContext(ctx) 32 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 33 | if templ_7745c5c3_Var1 == nil { 34 | templ_7745c5c3_Var1 = templ.NopComponent 35 | } 36 | ctx = templ.ClearChildren(ctx) 37 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(classes)} 38 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 39 | if templ_7745c5c3_Err != nil { 40 | return templ_7745c5c3_Err 41 | } 42 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 77 | if templ_7745c5c3_Err != nil { 78 | return templ_7745c5c3_Err 79 | } 80 | templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) 81 | if templ_7745c5c3_Err != nil { 82 | return templ_7745c5c3_Err 83 | } 84 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 85 | if templ_7745c5c3_Err != nil { 86 | return templ_7745c5c3_Err 87 | } 88 | return templ_7745c5c3_Err 89 | }) 90 | } 91 | 92 | // There is no element for collapsible trigger, just add these attributes to your component. 93 | var CollapsibleTriggerAttrs = templ.Attributes{ 94 | "x-data": true, 95 | "x-on:click": "shadcntempl_open = ! shadcntempl_open", 96 | ":aria-expanded": "shadcntempl_open", 97 | ":data-state": "shadcntempl_open ? 'open' : 'closed'", 98 | ":data-disabled": "shadcntempl_disabled", 99 | } 100 | 101 | func CollapsibleContent(classes string, attrs templ.Attributes) templ.Component { 102 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 103 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 104 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 105 | return templ_7745c5c3_CtxErr 106 | } 107 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 108 | if !templ_7745c5c3_IsBuffer { 109 | defer func() { 110 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 111 | if templ_7745c5c3_Err == nil { 112 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 113 | } 114 | }() 115 | } 116 | ctx = templ.InitializeContext(ctx) 117 | templ_7745c5c3_Var5 := templ.GetChildren(ctx) 118 | if templ_7745c5c3_Var5 == nil { 119 | templ_7745c5c3_Var5 = templ.NopComponent 120 | } 121 | ctx = templ.ClearChildren(ctx) 122 | var templ_7745c5c3_Var6 = []any{twmerge.Merge(classes)} 123 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...) 124 | if templ_7745c5c3_Err != nil { 125 | return templ_7745c5c3_Err 126 | } 127 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 149 | if templ_7745c5c3_Err != nil { 150 | return templ_7745c5c3_Err 151 | } 152 | templ_7745c5c3_Err = templ_7745c5c3_Var5.Render(ctx, templ_7745c5c3_Buffer) 153 | if templ_7745c5c3_Err != nil { 154 | return templ_7745c5c3_Err 155 | } 156 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 157 | if templ_7745c5c3_Err != nil { 158 | return templ_7745c5c3_Err 159 | } 160 | return templ_7745c5c3_Err 161 | }) 162 | } 163 | 164 | var _ = templruntime.GeneratedTemplate 165 | -------------------------------------------------------------------------------- /ui/dialog.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import ( 4 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 5 | "github.com/rotemhoresh/shadcn-templ/icons" 6 | ) 7 | 8 | const ( 9 | dialogContentBaseClass = "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 sm:rounded-lg fill-mode-forwards" 10 | dialogCloseBaseClass = "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none" 11 | dialogOverlayBaseClass = "fixed inset-0 z-50 bg-black/80 fill-mode-forwards" 12 | dialogHeaderBaseClass = "flex flex-col space-y-1.5 text-center sm:text-left" 13 | dialogFooterBaseClass = "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2" 14 | dialogTitleBaseClass = "text-lg font-semibold leading-none tracking-tight" 15 | dialogDescriptionBaseClass = "text-sm text-muted-foreground" 16 | ) 17 | 18 | templ Dialog(classes string, attrs templ.Attributes) { 19 |
    24 | { children... } 25 |
    26 | } 27 | 28 | // There is no element for dialog trigger, just add these attributes to your component. 29 | var DialogTriggerAttrs = templ.Attributes{ 30 | "aria-haspopup": "dialog", 31 | ":aria-expanded": "shadcntempl_open", 32 | "x-data": true, 33 | "x-on:click": "shadcntempl_open = true", 34 | } 35 | 36 | templ DialogContent(classes string, attrs templ.Attributes) { 37 | 45 | 70 | } 71 | 72 | // If you want to add a custom close, add this attributes to your component 73 | var DialogCloseAttrs = templ.Attributes{ 74 | "x-on:click": "shadcntempl_open = false", 75 | } 76 | 77 | templ DialogHeader(classes string, attrs templ.Attributes) { 78 |
    82 | { children... } 83 |
    84 | } 85 | 86 | templ DialogFooter(classes string, attrs templ.Attributes) { 87 |
    91 | { children... } 92 |
    93 | } 94 | 95 | templ DialogTitle(classes string, attrs templ.Attributes) { 96 |

    100 | { children... } 101 |

    102 | } 103 | 104 | templ DialogDescription(classes string, attrs templ.Attributes) { 105 |

    109 | { children... } 110 |

    111 | } 112 | -------------------------------------------------------------------------------- /ui/dialog/close.go: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import "github.com/rotemhoresh/shadcn-templ/primitives/dialog" 4 | 5 | var Close = dialog.Close 6 | -------------------------------------------------------------------------------- /ui/dialog/content.templ: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import ( 4 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 5 | "github.com/rotemhoresh/shadcn-templ/icons" 6 | "github.com/rotemhoresh/shadcn-templ/primitives/dialog" 7 | "github.com/rotemhoresh/shadcn-templ/primitives/portal" 8 | ) 9 | 10 | const ( 11 | contentClass = "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 sm:rounded-lg fill-mode-forwards" 12 | closeClass = "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none" 13 | ) 14 | 15 | type ContentProps = dialog.ContentProps 16 | 17 | func Content(props ContentProps) templ.Component { 18 | props.Class = twmerge.Merge(contentClass, props.Class) 19 | props.AddAttr("x-transition:enter", "animate-in fade-in-0 zoom-in-95 slide-in-from-top-[48%] slide-in-from-left-1/2") 20 | props.AddAttr("x-transition:leave", "animate-out fade-out-0 zoom-out-95 slide-out-to-top-[48%] slide-out-to-left-1/2") 21 | return content(props) 22 | } 23 | 24 | templ content(props ContentProps) { 25 | @portal.Root(portal.RootProps{}) { 26 | @Overlay(OverlayProps{}) 27 | } 28 | @portal.Root(portal.RootProps{}) { 29 | @dialog.Content(props) { 30 | { children... } 31 | 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ui/dialog/content_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package dialog 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 13 | "github.com/rotemhoresh/shadcn-templ/icons" 14 | "github.com/rotemhoresh/shadcn-templ/primitives/dialog" 15 | "github.com/rotemhoresh/shadcn-templ/primitives/portal" 16 | ) 17 | 18 | const ( 19 | contentClass = "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 sm:rounded-lg fill-mode-forwards" 20 | closeClass = "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none" 21 | ) 22 | 23 | type ContentProps = dialog.ContentProps 24 | 25 | func Content(props ContentProps) templ.Component { 26 | props.Class = twmerge.Merge(contentClass, props.Class) 27 | props.AddAttr("x-transition:enter", "animate-in fade-in-0 zoom-in-95 slide-in-from-top-[48%] slide-in-from-left-1/2") 28 | props.AddAttr("x-transition:leave", "animate-out fade-out-0 zoom-out-95 slide-out-to-top-[48%] slide-out-to-left-1/2") 29 | return content(props) 30 | } 31 | 32 | func content(props ContentProps) templ.Component { 33 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 34 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 35 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 36 | return templ_7745c5c3_CtxErr 37 | } 38 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 39 | if !templ_7745c5c3_IsBuffer { 40 | defer func() { 41 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 42 | if templ_7745c5c3_Err == nil { 43 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 44 | } 45 | }() 46 | } 47 | ctx = templ.InitializeContext(ctx) 48 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 49 | if templ_7745c5c3_Var1 == nil { 50 | templ_7745c5c3_Var1 = templ.NopComponent 51 | } 52 | ctx = templ.ClearChildren(ctx) 53 | templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 54 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 55 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 56 | if !templ_7745c5c3_IsBuffer { 57 | defer func() { 58 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 59 | if templ_7745c5c3_Err == nil { 60 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 61 | } 62 | }() 63 | } 64 | ctx = templ.InitializeContext(ctx) 65 | templ_7745c5c3_Err = Overlay(OverlayProps{}).Render(ctx, templ_7745c5c3_Buffer) 66 | if templ_7745c5c3_Err != nil { 67 | return templ_7745c5c3_Err 68 | } 69 | return templ_7745c5c3_Err 70 | }) 71 | templ_7745c5c3_Err = portal.Root(portal.RootProps{}).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 72 | if templ_7745c5c3_Err != nil { 73 | return templ_7745c5c3_Err 74 | } 75 | templ_7745c5c3_Var3 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 76 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 77 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 78 | if !templ_7745c5c3_IsBuffer { 79 | defer func() { 80 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 81 | if templ_7745c5c3_Err == nil { 82 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 83 | } 84 | }() 85 | } 86 | ctx = templ.InitializeContext(ctx) 87 | templ_7745c5c3_Var4 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 88 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 89 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 90 | if !templ_7745c5c3_IsBuffer { 91 | defer func() { 92 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 93 | if templ_7745c5c3_Err == nil { 94 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 95 | } 96 | }() 97 | } 98 | ctx = templ.InitializeContext(ctx) 99 | templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) 100 | if templ_7745c5c3_Err != nil { 101 | return templ_7745c5c3_Err 102 | } 103 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 104 | if templ_7745c5c3_Err != nil { 105 | return templ_7745c5c3_Err 106 | } 107 | var templ_7745c5c3_Var5 = []any{closeClass} 108 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var5...) 109 | if templ_7745c5c3_Err != nil { 110 | return templ_7745c5c3_Err 111 | } 112 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 144 | if templ_7745c5c3_Err != nil { 145 | return templ_7745c5c3_Err 146 | } 147 | return templ_7745c5c3_Err 148 | }) 149 | templ_7745c5c3_Err = dialog.Content(props).Render(templ.WithChildren(ctx, templ_7745c5c3_Var4), templ_7745c5c3_Buffer) 150 | if templ_7745c5c3_Err != nil { 151 | return templ_7745c5c3_Err 152 | } 153 | return templ_7745c5c3_Err 154 | }) 155 | templ_7745c5c3_Err = portal.Root(portal.RootProps{}).Render(templ.WithChildren(ctx, templ_7745c5c3_Var3), templ_7745c5c3_Buffer) 156 | if templ_7745c5c3_Err != nil { 157 | return templ_7745c5c3_Err 158 | } 159 | return templ_7745c5c3_Err 160 | }) 161 | } 162 | 163 | var _ = templruntime.GeneratedTemplate 164 | -------------------------------------------------------------------------------- /ui/dialog/description.templ: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import ( 4 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 5 | "github.com/rotemhoresh/shadcn-templ/primitives/dialog" 6 | ) 7 | 8 | const descriptionClass = "text-sm text-muted-foreground" 9 | 10 | type DescriptionProps = dialog.DescriptionProps 11 | 12 | func Description(props DescriptionProps) templ.Component { 13 | props.Class = twmerge.Merge(descriptionClass, props.Class) 14 | return dialog.Description(props) 15 | } 16 | -------------------------------------------------------------------------------- /ui/dialog/description_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package dialog 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 13 | "github.com/rotemhoresh/shadcn-templ/primitives/dialog" 14 | ) 15 | 16 | const descriptionClass = "text-sm text-muted-foreground" 17 | 18 | type DescriptionProps = dialog.DescriptionProps 19 | 20 | func Description(props DescriptionProps) templ.Component { 21 | props.Class = twmerge.Merge(descriptionClass, props.Class) 22 | return dialog.Description(props) 23 | } 24 | 25 | var _ = templruntime.GeneratedTemplate 26 | -------------------------------------------------------------------------------- /ui/dialog/footer.templ: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import ( 4 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 5 | p "github.com/rotemhoresh/shadcn-templ/primitives" 6 | ) 7 | 8 | const footerClass = "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2" 9 | 10 | type FooterProps struct { 11 | p.CoreProps 12 | } 13 | 14 | templ Footer(props FooterProps) { 15 |
    19 | { children... } 20 |
    21 | } 22 | -------------------------------------------------------------------------------- /ui/dialog/footer_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package dialog 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 13 | p "github.com/rotemhoresh/shadcn-templ/primitives" 14 | ) 15 | 16 | const footerClass = "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2" 17 | 18 | type FooterProps struct { 19 | p.CoreProps 20 | } 21 | 22 | func Footer(props FooterProps) templ.Component { 23 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 24 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 25 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 26 | return templ_7745c5c3_CtxErr 27 | } 28 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 29 | if !templ_7745c5c3_IsBuffer { 30 | defer func() { 31 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 32 | if templ_7745c5c3_Err == nil { 33 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 34 | } 35 | }() 36 | } 37 | ctx = templ.InitializeContext(ctx) 38 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 39 | if templ_7745c5c3_Var1 == nil { 40 | templ_7745c5c3_Var1 = templ.NopComponent 41 | } 42 | ctx = templ.ClearChildren(ctx) 43 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(footerClass, props.Class)} 44 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 45 | if templ_7745c5c3_Err != nil { 46 | return templ_7745c5c3_Err 47 | } 48 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 70 | if templ_7745c5c3_Err != nil { 71 | return templ_7745c5c3_Err 72 | } 73 | templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) 74 | if templ_7745c5c3_Err != nil { 75 | return templ_7745c5c3_Err 76 | } 77 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 78 | if templ_7745c5c3_Err != nil { 79 | return templ_7745c5c3_Err 80 | } 81 | return templ_7745c5c3_Err 82 | }) 83 | } 84 | 85 | var _ = templruntime.GeneratedTemplate 86 | -------------------------------------------------------------------------------- /ui/dialog/header.templ: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import ( 4 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 5 | p "github.com/rotemhoresh/shadcn-templ/primitives" 6 | ) 7 | 8 | const headerClass = "flex flex-col space-y-1.5 text-center sm:text-left" 9 | 10 | type HeaderProps struct { 11 | p.CoreProps 12 | } 13 | 14 | templ Header(props HeaderProps) { 15 |
    19 | { children... } 20 |
    21 | } 22 | -------------------------------------------------------------------------------- /ui/dialog/header_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package dialog 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 13 | p "github.com/rotemhoresh/shadcn-templ/primitives" 14 | ) 15 | 16 | const headerClass = "flex flex-col space-y-1.5 text-center sm:text-left" 17 | 18 | type HeaderProps struct { 19 | p.CoreProps 20 | } 21 | 22 | func Header(props HeaderProps) templ.Component { 23 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 24 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 25 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 26 | return templ_7745c5c3_CtxErr 27 | } 28 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 29 | if !templ_7745c5c3_IsBuffer { 30 | defer func() { 31 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 32 | if templ_7745c5c3_Err == nil { 33 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 34 | } 35 | }() 36 | } 37 | ctx = templ.InitializeContext(ctx) 38 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 39 | if templ_7745c5c3_Var1 == nil { 40 | templ_7745c5c3_Var1 = templ.NopComponent 41 | } 42 | ctx = templ.ClearChildren(ctx) 43 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(headerClass, props.Class)} 44 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 45 | if templ_7745c5c3_Err != nil { 46 | return templ_7745c5c3_Err 47 | } 48 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 70 | if templ_7745c5c3_Err != nil { 71 | return templ_7745c5c3_Err 72 | } 73 | templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) 74 | if templ_7745c5c3_Err != nil { 75 | return templ_7745c5c3_Err 76 | } 77 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 78 | if templ_7745c5c3_Err != nil { 79 | return templ_7745c5c3_Err 80 | } 81 | return templ_7745c5c3_Err 82 | }) 83 | } 84 | 85 | var _ = templruntime.GeneratedTemplate 86 | -------------------------------------------------------------------------------- /ui/dialog/overlay.templ: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import ( 4 | twmerge "github.com/Oudwins/tailwind-merge-go" 5 | "github.com/rotemhoresh/shadcn-templ/primitives/dialog" 6 | ) 7 | 8 | const overlayClass = "fixed inset-0 z-50 bg-black/80 fill-mode-forwards" 9 | 10 | type OverlayProps = dialog.OverlayProps 11 | 12 | func Overlay(props OverlayProps) templ.Component { 13 | props.Class = twmerge.Merge(overlayClass, props.Class) 14 | props.AddAttr("x-transition:enter", "animate-in fade-in-0") 15 | props.AddAttr("x-transition:leave", "animate-out fade-out-0") 16 | return dialog.Overlay(props) 17 | } 18 | -------------------------------------------------------------------------------- /ui/dialog/overlay_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package dialog 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | twmerge "github.com/Oudwins/tailwind-merge-go" 13 | "github.com/rotemhoresh/shadcn-templ/primitives/dialog" 14 | ) 15 | 16 | const overlayClass = "fixed inset-0 z-50 bg-black/80 fill-mode-forwards" 17 | 18 | type OverlayProps = dialog.OverlayProps 19 | 20 | func Overlay(props OverlayProps) templ.Component { 21 | props.Class = twmerge.Merge(overlayClass, props.Class) 22 | props.AddAttr("x-transition:enter", "animate-in fade-in-0") 23 | props.AddAttr("x-transition:leave", "animate-out fade-out-0") 24 | return dialog.Overlay(props) 25 | } 26 | 27 | var _ = templruntime.GeneratedTemplate 28 | -------------------------------------------------------------------------------- /ui/dialog/root.go: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import "github.com/rotemhoresh/shadcn-templ/primitives/dialog" 4 | 5 | type RootProps = dialog.RootProps 6 | 7 | var Root = dialog.Root 8 | -------------------------------------------------------------------------------- /ui/dialog/title.templ: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import ( 4 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 5 | "github.com/rotemhoresh/shadcn-templ/primitives/dialog" 6 | ) 7 | 8 | const titleClass = "text-lg font-semibold leading-none tracking-tight" 9 | 10 | type TitleProps = dialog.TitleProps 11 | 12 | func Title(props TitleProps) templ.Component { 13 | props.Class = twmerge.Merge(titleClass, props.Class) 14 | return dialog.Title(props) 15 | } 16 | -------------------------------------------------------------------------------- /ui/dialog/title_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package dialog 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 13 | "github.com/rotemhoresh/shadcn-templ/primitives/dialog" 14 | ) 15 | 16 | const titleClass = "text-lg font-semibold leading-none tracking-tight" 17 | 18 | type TitleProps = dialog.TitleProps 19 | 20 | func Title(props TitleProps) templ.Component { 21 | props.Class = twmerge.Merge(titleClass, props.Class) 22 | return dialog.Title(props) 23 | } 24 | 25 | var _ = templruntime.GeneratedTemplate 26 | -------------------------------------------------------------------------------- /ui/dialog/trigger.go: -------------------------------------------------------------------------------- 1 | package dialog 2 | 3 | import "github.com/rotemhoresh/shadcn-templ/primitives/dialog" 4 | 5 | var Trigger = dialog.Trigger 6 | -------------------------------------------------------------------------------- /ui/dropdown-menu.templ: -------------------------------------------------------------------------------- 1 | package ui; 2 | 3 | import twmerge "github.com/Oudwins/tailwind-merge-go" 4 | 5 | // TODO: add side alignment options 6 | 7 | type DropdownMenuAlign int 8 | 9 | func (a DropdownMenuAlign) Class() string { 10 | switch a { 11 | case DropdownMenuAlignLeft: 12 | return "left-0" 13 | case DropdownMenuAlignRight: 14 | return "right-0" 15 | default: 16 | return "left-1/2 -translate-x-1/2" 17 | } 18 | } 19 | 20 | const ( 21 | DropdownMenuAlignCenter DropdownMenuAlign = iota 22 | DropdownMenuAlignLeft 23 | DropdownMenuAlignRight 24 | ) 25 | 26 | const ( 27 | dropdownMenuContentBaseClass = "absolute botton-full mt-2 z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md focus:outline-none" 28 | dropdownMenuItemBaseClass = "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground" 29 | dropdownMenuSeparatorBaseClass = "-mx-1 my-1 h-px bg-muted" 30 | dropdownMenuShortcutBaseClass = "ml-auto text-xs tracking-widest opacity-60" 31 | dropdownMenuLabelBaseClass = "px-2 py-1.5 text-sm font-semibold" 32 | ) 33 | 34 | templ DropdownMenu(classes string, attrs templ.Attributes) { 35 |
    41 | { children... } 42 |
    43 | } 44 | 45 | // There is no element for dropdown menu trigger, just add these attributes to your component. 46 | var DropdownMenuTriggerAttrs = templ.Attributes{ 47 | "x-on:mousedown": "open = true", 48 | "aria-haspopup": "menu", 49 | ":aria-expanded": "open", 50 | "x-data": true, 51 | "x-on:keydown.enter.prevent": "open = true", 52 | "x-on:keydown.space.prevent": "open = true", 53 | "x-on:keydown.down.prevent": "open = true", 54 | } 55 | 56 | templ DropdownMenuContent(align DropdownMenuAlign, classes string, attrs templ.Attributes) { 57 | 71 | } 72 | 73 | templ DropdownMenuItem(classes string, attrs templ.Attributes) { 74 |
    82 | { children... } 83 |
    84 | } 85 | 86 | templ DropdownMenuSeparator(classes string, attrs templ.Attributes) { 87 |
    91 | } 92 | 93 | templ DropdownMenuShortcut(classes string, attrs templ.Attributes) { 94 | 98 | { children... } 99 | 100 | } 101 | 102 | templ DropdownMenuLabel(classes string, attrs templ.Attributes) { 103 |
    107 | { children... } 108 |
    109 | } 110 | -------------------------------------------------------------------------------- /ui/field.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 4 | 5 | const ( 6 | fieldDescriptionBaseClass = "text-[0.8rem] text-muted-foreground" 7 | fieldErrorBaseClass = "text-[0.8rem] font-medium text-destructive" 8 | fieldBaseClass = "space-y-2" 9 | ) 10 | 11 | templ FieldDescription(classes string, attrs templ.Attributes) { 12 |
    16 | { children... } 17 |
    18 | } 19 | 20 | // `id` is for [hx-swap-oob], if not needed, set it to an empty string (i.e., "") 21 | // 22 | // [hx-swap-oob]: https://htmx.org/attributes/hx-swap-oob 23 | templ FieldError(id, classes string, attrs templ.Attributes) { 24 |
    33 | { children... } 34 |
    35 | } 36 | 37 | templ Field(classes string, attrs templ.Attributes) { 38 |
    42 | { children... } 43 |
    44 | } 45 | -------------------------------------------------------------------------------- /ui/field_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package ui 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 12 | 13 | const ( 14 | fieldDescriptionBaseClass = "text-[0.8rem] text-muted-foreground" 15 | fieldErrorBaseClass = "text-[0.8rem] font-medium text-destructive" 16 | fieldBaseClass = "space-y-2" 17 | ) 18 | 19 | func FieldDescription(classes string, attrs templ.Attributes) templ.Component { 20 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 21 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 22 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 23 | return templ_7745c5c3_CtxErr 24 | } 25 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 26 | if !templ_7745c5c3_IsBuffer { 27 | defer func() { 28 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 29 | if templ_7745c5c3_Err == nil { 30 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 31 | } 32 | }() 33 | } 34 | ctx = templ.InitializeContext(ctx) 35 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 36 | if templ_7745c5c3_Var1 == nil { 37 | templ_7745c5c3_Var1 = templ.NopComponent 38 | } 39 | ctx = templ.ClearChildren(ctx) 40 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(fieldDescriptionBaseClass, classes)} 41 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 42 | if templ_7745c5c3_Err != nil { 43 | return templ_7745c5c3_Err 44 | } 45 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 67 | if templ_7745c5c3_Err != nil { 68 | return templ_7745c5c3_Err 69 | } 70 | templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) 71 | if templ_7745c5c3_Err != nil { 72 | return templ_7745c5c3_Err 73 | } 74 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 75 | if templ_7745c5c3_Err != nil { 76 | return templ_7745c5c3_Err 77 | } 78 | return templ_7745c5c3_Err 79 | }) 80 | } 81 | 82 | // `id` is for [hx-swap-oob], if not needed, set it to an empty string (i.e., "") 83 | // 84 | // [hx-swap-oob]: https://htmx.org/attributes/hx-swap-oob 85 | func FieldError(id, classes string, attrs templ.Attributes) templ.Component { 86 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 87 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 88 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 89 | return templ_7745c5c3_CtxErr 90 | } 91 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 92 | if !templ_7745c5c3_IsBuffer { 93 | defer func() { 94 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 95 | if templ_7745c5c3_Err == nil { 96 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 97 | } 98 | }() 99 | } 100 | ctx = templ.InitializeContext(ctx) 101 | templ_7745c5c3_Var4 := templ.GetChildren(ctx) 102 | if templ_7745c5c3_Var4 == nil { 103 | templ_7745c5c3_Var4 = templ.NopComponent 104 | } 105 | ctx = templ.ClearChildren(ctx) 106 | var templ_7745c5c3_Var5 = []any{twmerge.Merge(fieldErrorBaseClass, classes)} 107 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var5...) 108 | if templ_7745c5c3_Err != nil { 109 | return templ_7745c5c3_Err 110 | } 111 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 152 | if templ_7745c5c3_Err != nil { 153 | return templ_7745c5c3_Err 154 | } 155 | templ_7745c5c3_Err = templ_7745c5c3_Var4.Render(ctx, templ_7745c5c3_Buffer) 156 | if templ_7745c5c3_Err != nil { 157 | return templ_7745c5c3_Err 158 | } 159 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 160 | if templ_7745c5c3_Err != nil { 161 | return templ_7745c5c3_Err 162 | } 163 | return templ_7745c5c3_Err 164 | }) 165 | } 166 | 167 | func Field(classes string, attrs templ.Attributes) templ.Component { 168 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 169 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 170 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 171 | return templ_7745c5c3_CtxErr 172 | } 173 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 174 | if !templ_7745c5c3_IsBuffer { 175 | defer func() { 176 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 177 | if templ_7745c5c3_Err == nil { 178 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 179 | } 180 | }() 181 | } 182 | ctx = templ.InitializeContext(ctx) 183 | templ_7745c5c3_Var8 := templ.GetChildren(ctx) 184 | if templ_7745c5c3_Var8 == nil { 185 | templ_7745c5c3_Var8 = templ.NopComponent 186 | } 187 | ctx = templ.ClearChildren(ctx) 188 | var templ_7745c5c3_Var9 = []any{twmerge.Merge(fieldBaseClass, classes)} 189 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var9...) 190 | if templ_7745c5c3_Err != nil { 191 | return templ_7745c5c3_Err 192 | } 193 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 215 | if templ_7745c5c3_Err != nil { 216 | return templ_7745c5c3_Err 217 | } 218 | templ_7745c5c3_Err = templ_7745c5c3_Var8.Render(ctx, templ_7745c5c3_Buffer) 219 | if templ_7745c5c3_Err != nil { 220 | return templ_7745c5c3_Err 221 | } 222 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 223 | if templ_7745c5c3_Err != nil { 224 | return templ_7745c5c3_Err 225 | } 226 | return templ_7745c5c3_Err 227 | }) 228 | } 229 | 230 | var _ = templruntime.GeneratedTemplate 231 | -------------------------------------------------------------------------------- /ui/input.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 4 | 5 | const ( 6 | inputBaseClass = "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50" 7 | ) 8 | 9 | type InputType int 10 | 11 | const ( 12 | InputTypeText InputType = iota 13 | InputTypeEmail 14 | InputTypePassword 15 | InputTypeSearch 16 | InputTypeUrl 17 | InputTypeTel 18 | InputTypeDate 19 | InputTypeDatetimeLocal 20 | InputTypeNumber 21 | InputTypeButton 22 | InputTypeFile 23 | InputTypeHidden 24 | InputTypeImage 25 | InputTypeMonth 26 | InputTypeWeek 27 | InputTypeCheckbox 28 | InputTypeColor 29 | InputTypeRadio 30 | InputTypeRange 31 | InputTypeReset 32 | InputTypeSubmit 33 | InputTypeTime 34 | ) 35 | 36 | func (t InputType) String() string { 37 | switch t { 38 | case InputTypeEmail: 39 | return "email" 40 | case InputTypePassword: 41 | return "password" 42 | case InputTypeSearch: 43 | return "search" 44 | case InputTypeUrl: 45 | return "url" 46 | case InputTypeTel: 47 | return "tel" 48 | case InputTypeDate: 49 | return "date" 50 | case InputTypeDatetimeLocal: 51 | return "datetime-local" 52 | case InputTypeNumber: 53 | return "number" 54 | case InputTypeButton: 55 | return "button" 56 | case InputTypeFile: 57 | return "file" 58 | case InputTypeHidden: 59 | return "hidden" 60 | case InputTypeImage: 61 | return "image" 62 | case InputTypeMonth: 63 | return "month" 64 | case InputTypeWeek: 65 | return "week" 66 | case InputTypeCheckbox: 67 | return "checkbox" 68 | case InputTypeColor: 69 | return "color" 70 | case InputTypeRadio: 71 | return "radio" 72 | case InputTypeRange: 73 | return "range" 74 | case InputTypeReset: 75 | return "reset" 76 | case InputTypeSubmit: 77 | return "submit" 78 | case InputTypeTime: 79 | return "time" 80 | default: 81 | return "text" 82 | } 83 | } 84 | 85 | templ Input(name string, inputType InputType, classes string, attrs templ.Attributes) { 86 | 92 | } 93 | -------------------------------------------------------------------------------- /ui/input_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package ui 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 12 | 13 | const ( 14 | inputBaseClass = "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50" 15 | ) 16 | 17 | type InputType int 18 | 19 | const ( 20 | InputTypeText InputType = iota 21 | InputTypeEmail 22 | InputTypePassword 23 | InputTypeSearch 24 | InputTypeUrl 25 | InputTypeTel 26 | InputTypeDate 27 | InputTypeDatetimeLocal 28 | InputTypeNumber 29 | InputTypeButton 30 | InputTypeFile 31 | InputTypeHidden 32 | InputTypeImage 33 | InputTypeMonth 34 | InputTypeWeek 35 | InputTypeCheckbox 36 | InputTypeColor 37 | InputTypeRadio 38 | InputTypeRange 39 | InputTypeReset 40 | InputTypeSubmit 41 | InputTypeTime 42 | ) 43 | 44 | func (t InputType) String() string { 45 | switch t { 46 | case InputTypeEmail: 47 | return "email" 48 | case InputTypePassword: 49 | return "password" 50 | case InputTypeSearch: 51 | return "search" 52 | case InputTypeUrl: 53 | return "url" 54 | case InputTypeTel: 55 | return "tel" 56 | case InputTypeDate: 57 | return "date" 58 | case InputTypeDatetimeLocal: 59 | return "datetime-local" 60 | case InputTypeNumber: 61 | return "number" 62 | case InputTypeButton: 63 | return "button" 64 | case InputTypeFile: 65 | return "file" 66 | case InputTypeHidden: 67 | return "hidden" 68 | case InputTypeImage: 69 | return "image" 70 | case InputTypeMonth: 71 | return "month" 72 | case InputTypeWeek: 73 | return "week" 74 | case InputTypeCheckbox: 75 | return "checkbox" 76 | case InputTypeColor: 77 | return "color" 78 | case InputTypeRadio: 79 | return "radio" 80 | case InputTypeRange: 81 | return "range" 82 | case InputTypeReset: 83 | return "reset" 84 | case InputTypeSubmit: 85 | return "submit" 86 | case InputTypeTime: 87 | return "time" 88 | default: 89 | return "text" 90 | } 91 | } 92 | 93 | func Input(name string, inputType InputType, classes string, attrs templ.Attributes) templ.Component { 94 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 95 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 96 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 97 | return templ_7745c5c3_CtxErr 98 | } 99 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 100 | if !templ_7745c5c3_IsBuffer { 101 | defer func() { 102 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 103 | if templ_7745c5c3_Err == nil { 104 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 105 | } 106 | }() 107 | } 108 | ctx = templ.InitializeContext(ctx) 109 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 110 | if templ_7745c5c3_Var1 == nil { 111 | templ_7745c5c3_Var1 = templ.NopComponent 112 | } 113 | ctx = templ.ClearChildren(ctx) 114 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(inputBaseClass, classes)} 115 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 116 | if templ_7745c5c3_Err != nil { 117 | return templ_7745c5c3_Err 118 | } 119 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 167 | if templ_7745c5c3_Err != nil { 168 | return templ_7745c5c3_Err 169 | } 170 | return templ_7745c5c3_Err 171 | }) 172 | } 173 | 174 | var _ = templruntime.GeneratedTemplate 175 | -------------------------------------------------------------------------------- /ui/label.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 4 | 5 | const ( 6 | labelBaseClass = "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 7 | ) 8 | 9 | templ Label(classes string, attrs templ.Attributes) { 10 | 16 | } 17 | -------------------------------------------------------------------------------- /ui/label_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package ui 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 12 | 13 | const ( 14 | labelBaseClass = "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 15 | ) 16 | 17 | func Label(classes string, attrs templ.Attributes) templ.Component { 18 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 19 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 20 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 21 | return templ_7745c5c3_CtxErr 22 | } 23 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 24 | if !templ_7745c5c3_IsBuffer { 25 | defer func() { 26 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 27 | if templ_7745c5c3_Err == nil { 28 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 29 | } 30 | }() 31 | } 32 | ctx = templ.InitializeContext(ctx) 33 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 34 | if templ_7745c5c3_Var1 == nil { 35 | templ_7745c5c3_Var1 = templ.NopComponent 36 | } 37 | ctx = templ.ClearChildren(ctx) 38 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(labelBaseClass, "[div:has(>div.font-medium:not(:empty))>&]:text-destructive", classes)} 39 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 40 | if templ_7745c5c3_Err != nil { 41 | return templ_7745c5c3_Err 42 | } 43 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 73 | if templ_7745c5c3_Err != nil { 74 | return templ_7745c5c3_Err 75 | } 76 | return templ_7745c5c3_Err 77 | }) 78 | } 79 | 80 | var _ = templruntime.GeneratedTemplate 81 | -------------------------------------------------------------------------------- /ui/optalias_generator.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | // +build ignore 3 | 4 | package main 5 | 6 | import ( 7 | "flag" 8 | "fmt" 9 | "go/ast" 10 | "go/parser" 11 | "go/token" 12 | "os" 13 | "os/exec" 14 | "path/filepath" 15 | "strings" 16 | ) 17 | 18 | const filePath = "../props.go" 19 | 20 | func main() { 21 | var typeFlag string 22 | flag.StringVar(&typeFlag, "type", "", "type name to set aliases with as type param") 23 | flag.Parse() 24 | 25 | if typeFlag == "" || filePath == "" { 26 | panic("Both type and path parameters must be provided") 27 | } 28 | 29 | fset := token.NewFileSet() 30 | node, err := parser.ParseFile(fset, filePath, nil, parser.ParseComments) 31 | if err != nil { 32 | panic(err) 33 | } 34 | 35 | packageName := node.Name.Name 36 | 37 | var functions []string 38 | 39 | for _, decl := range node.Decls { 40 | if fn, ok := decl.(*ast.FuncDecl); ok { 41 | // Check if the function return type is of the desired type 42 | if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 { 43 | returnType := fn.Type.Results.List[0].Type 44 | if isMatchingType(returnType) { 45 | functions = append(functions, fn.Name.Name) 46 | } 47 | } 48 | } 49 | } 50 | 51 | cwd, err := os.Getwd() 52 | if err != nil { 53 | panic(err) 54 | } 55 | outputFilePath := filepath.Join(cwd, "generated_optaliase.go") 56 | f, err := os.Create(outputFilePath) 57 | if err != nil { 58 | panic(err) 59 | } 60 | 61 | var b strings.Builder 62 | mustWrite(&b, "// Code generated by \"optaliase_generator.go %s\"; DO NOT EDIT.\n", strings.Join(os.Args[1:], " ")) 63 | mustWrite(&b, "\n") 64 | mustWrite(&b, "package %s", currPackageName()) 65 | mustWrite(&b, "\n") 66 | mustWrite(&b, "var (\n") 67 | for _, function := range functions { 68 | mustWrite(&b, " %s = %s.%s[*%s]\n", function, packageName, function, typeFlag) 69 | } 70 | mustWrite(&b, ")") 71 | 72 | if _, err = f.WriteString(b.String()); err != nil { 73 | panic(err) 74 | } 75 | 76 | if err = f.Close(); err != nil { 77 | panic(err) 78 | } 79 | 80 | runGoImports(outputFilePath) 81 | } 82 | 83 | // panics at any error 84 | func runGoImports(filePath string) { 85 | cmd := exec.Command("goimports", "-w", filePath) // -w flag writes the result back to the file 86 | if err := cmd.Run(); err != nil { 87 | panic(err) 88 | } 89 | } 90 | 91 | func mustWrite(b *strings.Builder, f string, a ...any) { 92 | if _, err := b.WriteString(fmt.Sprintf(f, a...)); err != nil { 93 | panic(err) 94 | } 95 | } 96 | 97 | // checks if the type is `*Option` 98 | func isMatchingType(typ ast.Expr) bool { 99 | // Handle pointer types 100 | if indexExpr, ok := typ.(*ast.IndexExpr); ok { 101 | if ident, ok := indexExpr.X.(*ast.Ident); ok { 102 | if ident.Name == "Option" { 103 | return true 104 | } 105 | } 106 | } 107 | return false 108 | } 109 | 110 | // will panic at any error 111 | func currPackageName() string { 112 | currentDir, err := os.Getwd() 113 | if err != nil { 114 | panic(err) 115 | } 116 | 117 | goFiles, err := filepath.Glob(filepath.Join(currentDir, "*.go")) 118 | if err != nil || len(goFiles) == 0 { 119 | panic(err) 120 | } 121 | 122 | var firstGoFile string 123 | for _, goFile := range goFiles { 124 | if filepath.Base(goFile) != "generated_optaliase.go" { 125 | firstGoFile = goFile 126 | break 127 | } 128 | } 129 | if firstGoFile == "" { 130 | panic("no files found in cwd") 131 | } 132 | 133 | fset := token.NewFileSet() 134 | node, err := parser.ParseFile(fset, firstGoFile, nil, parser.PackageClauseOnly) 135 | if err != nil { 136 | panic(err) 137 | } 138 | 139 | return node.Name.Name 140 | } 141 | -------------------------------------------------------------------------------- /ui/progress/generated_optaliase.go: -------------------------------------------------------------------------------- 1 | // Code generated by "optaliase_generator.go -type=RootProps"; DO NOT EDIT. 2 | 3 | package progress 4 | 5 | import "github.com/rotemhoresh/shadcn-templ/ui" 6 | 7 | var ( 8 | WithClass = ui.WithClass[*RootProps] 9 | WithAttrs = ui.WithAttrs[*RootProps] 10 | WithAttr = ui.WithAttr[*RootProps] 11 | ) 12 | -------------------------------------------------------------------------------- /ui/progress/root.templ: -------------------------------------------------------------------------------- 1 | package progress 2 | 3 | import ( 4 | "fmt" 5 | twmerge "github.com/Oudwins/tailwind-merge-go" 6 | "github.com/rotemhoresh/shadcn-templ/ui" 7 | ) 8 | 9 | const ( 10 | baseClass = "relative h-2 w-full overflow-hidden rounded-full bg-primary/20" 11 | indicatorBaseClass = "h-full w-full flex-1 bg-primary transition-all" 12 | ) 13 | 14 | const maxVal uint = 100 15 | 16 | type RootProps struct { 17 | control string 18 | value uint 19 | ui.CoreProps 20 | } 21 | 22 | type RootOption = ui.Option[*RootProps] 23 | 24 | // provide a controling variable created using `x-data` on a parent component 25 | func WithControl(c string) RootOption { 26 | return func(p *RootProps) { 27 | p.control = c 28 | } 29 | } 30 | 31 | // if a control is provided, `value` will be ignored. 32 | // 33 | // default value - 0 34 | func WithValue(v uint) RootOption { 35 | return func(p *RootProps) { 36 | p.value = v 37 | } 38 | } 39 | 40 | //go:generate go run ../optalias_generator.go -type=RootProps 41 | 42 | func Root(opts ...RootOption) templ.Component { 43 | p := &RootProps{ 44 | CoreProps: ui.DefaultCoreProps, 45 | } 46 | for _, opt := range opts { 47 | opt(p) 48 | } 49 | return root(p) 50 | } 51 | 52 | css uncontrolledIndicatorStyle(v uint) { 53 | transform: { fmt.Sprintf("translateX(%d)", -1 * (100 - int(v))) }; 54 | } 55 | 56 | templ root(props *RootProps) { 57 |
    80 |
    97 |
    98 | } 99 | -------------------------------------------------------------------------------- /ui/props.go: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import "github.com/a-h/templ" 4 | 5 | type Option[T CorePropsInter] func(T) 6 | 7 | // Sets the class 8 | func WithClass[T CorePropsInter](c string) Option[T] { 9 | return func(p T) { 10 | p.SetClass(c) 11 | } 12 | } 13 | 14 | // Sets the attributes 15 | func WithAttrs[T CorePropsInter](a templ.Attributes) Option[T] { 16 | return func(p T) { 17 | p.SetAttrs(a) 18 | } 19 | } 20 | 21 | // Adds an attribute 22 | func WithAttr[T CorePropsInter](k string, v any) Option[T] { 23 | return func(p T) { 24 | p.SetAttr(k, v) 25 | } 26 | } 27 | 28 | type CoreProps struct { 29 | class string 30 | attrs templ.Attributes 31 | } 32 | 33 | var DefaultCoreProps = CoreProps{ 34 | class: "", 35 | attrs: templ.Attributes{}, 36 | } 37 | 38 | var _ CorePropsInter = (*CoreProps)(nil) 39 | 40 | type CorePropsInter interface { 41 | SetClass(string) 42 | SetAttrs(templ.Attributes) 43 | SetAttr(string, any) 44 | Class() string 45 | Attrs() templ.Attributes 46 | } 47 | 48 | func (p *CoreProps) SetClass(c string) { 49 | p.class = c 50 | } 51 | 52 | func (p *CoreProps) SetAttrs(a templ.Attributes) { 53 | p.attrs = a 54 | } 55 | 56 | func (p *CoreProps) SetAttr(k string, v any) { 57 | p.attrs[k] = v 58 | } 59 | 60 | func (p *CoreProps) Class() string { 61 | return p.class 62 | } 63 | 64 | func (p *CoreProps) Attrs() templ.Attributes { 65 | return p.attrs 66 | } 67 | -------------------------------------------------------------------------------- /ui/separator.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 4 | 5 | const ( 6 | separatorBaseClass = "shrink-0 bg-border" 7 | ) 8 | 9 | type SeparatorOrientation int 10 | 11 | func (o SeparatorOrientation) String() string { 12 | switch o { 13 | case SeparatorOrientationVertical: 14 | return "vertical" 15 | default: 16 | return "horizontal" 17 | } 18 | } 19 | 20 | func (o SeparatorOrientation) Class() string { 21 | switch o { 22 | case SeparatorOrientationVertical: 23 | return "h-full w-[1px]" 24 | default: 25 | return "h-[1px] w-full" 26 | } 27 | } 28 | 29 | const ( 30 | SeparatorOrientationVertical SeparatorOrientation = iota 31 | SeparatorOrientationHorizontal 32 | ) 33 | 34 | templ Separator(orientation SeparatorOrientation, decorative bool, classes string, attrs templ.Attributes) { 35 |
    44 | } 45 | -------------------------------------------------------------------------------- /ui/separator_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package ui 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 12 | 13 | const ( 14 | separatorBaseClass = "shrink-0 bg-border" 15 | ) 16 | 17 | type SeparatorOrientation int 18 | 19 | func (o SeparatorOrientation) String() string { 20 | switch o { 21 | case SeparatorOrientationVertical: 22 | return "vertical" 23 | default: 24 | return "horizontal" 25 | } 26 | } 27 | 28 | func (o SeparatorOrientation) Class() string { 29 | switch o { 30 | case SeparatorOrientationVertical: 31 | return "h-full w-[1px]" 32 | default: 33 | return "h-[1px] w-full" 34 | } 35 | } 36 | 37 | const ( 38 | SeparatorOrientationVertical SeparatorOrientation = iota 39 | SeparatorOrientationHorizontal 40 | ) 41 | 42 | func Separator(orientation SeparatorOrientation, decorative bool, classes string, attrs templ.Attributes) templ.Component { 43 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 44 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 45 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 46 | return templ_7745c5c3_CtxErr 47 | } 48 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 49 | if !templ_7745c5c3_IsBuffer { 50 | defer func() { 51 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 52 | if templ_7745c5c3_Err == nil { 53 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 54 | } 55 | }() 56 | } 57 | ctx = templ.InitializeContext(ctx) 58 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 59 | if templ_7745c5c3_Var1 == nil { 60 | templ_7745c5c3_Var1 = templ.NopComponent 61 | } 62 | ctx = templ.ClearChildren(ctx) 63 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(separatorBaseClass, orientation.Class(), classes)} 64 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 65 | if templ_7745c5c3_Err != nil { 66 | return templ_7745c5c3_Err 67 | } 68 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 110 | if templ_7745c5c3_Err != nil { 111 | return templ_7745c5c3_Err 112 | } 113 | return templ_7745c5c3_Err 114 | }) 115 | } 116 | 117 | var _ = templruntime.GeneratedTemplate 118 | -------------------------------------------------------------------------------- /ui/skeleton.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import "github.com/Oudwins/tailwind-merge-go" 4 | 5 | const ( 6 | skeletonBaseClass = "animate-pulse rounded-md bg-primary/10" 7 | ) 8 | 9 | templ Skeleton(classes string, attrs templ.Attributes) { 10 |
    14 | } 15 | -------------------------------------------------------------------------------- /ui/skeleton_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package ui 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import "github.com/Oudwins/tailwind-merge-go" 12 | 13 | const ( 14 | skeletonBaseClass = "animate-pulse rounded-md bg-primary/10" 15 | ) 16 | 17 | func Skeleton(classes string, attrs templ.Attributes) templ.Component { 18 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 19 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 20 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 21 | return templ_7745c5c3_CtxErr 22 | } 23 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 24 | if !templ_7745c5c3_IsBuffer { 25 | defer func() { 26 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 27 | if templ_7745c5c3_Err == nil { 28 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 29 | } 30 | }() 31 | } 32 | ctx = templ.InitializeContext(ctx) 33 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 34 | if templ_7745c5c3_Var1 == nil { 35 | templ_7745c5c3_Var1 = templ.NopComponent 36 | } 37 | ctx = templ.ClearChildren(ctx) 38 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(skeletonBaseClass, classes)} 39 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 40 | if templ_7745c5c3_Err != nil { 41 | return templ_7745c5c3_Err 42 | } 43 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 65 | if templ_7745c5c3_Err != nil { 66 | return templ_7745c5c3_Err 67 | } 68 | return templ_7745c5c3_Err 69 | }) 70 | } 71 | 72 | var _ = templruntime.GeneratedTemplate 73 | -------------------------------------------------------------------------------- /ui/switch.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import ( 4 | "fmt" 5 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 6 | ) 7 | 8 | const ( 9 | switchBaseClass = "peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input" 10 | switchThumbBaseClass = "pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0" 11 | ) 12 | 13 | // `attrs` will go to the inner input 14 | templ Switch(name string, defaultChecked, required bool, classes string, attrs templ.Attributes) { 15 | 48 | } 49 | 50 | templ switchThumb(disabled bool) { 51 | 59 | } 60 | -------------------------------------------------------------------------------- /ui/switch_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package ui 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | "fmt" 13 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 14 | ) 15 | 16 | const ( 17 | switchBaseClass = "peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input" 18 | switchThumbBaseClass = "pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0" 19 | ) 20 | 21 | // `attrs` will go to the inner input 22 | func Switch(name string, defaultChecked, required bool, classes string, attrs templ.Attributes) templ.Component { 23 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 24 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 25 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 26 | return templ_7745c5c3_CtxErr 27 | } 28 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 29 | if !templ_7745c5c3_IsBuffer { 30 | defer func() { 31 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 32 | if templ_7745c5c3_Err == nil { 33 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 34 | } 35 | }() 36 | } 37 | ctx = templ.InitializeContext(ctx) 38 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 39 | if templ_7745c5c3_Var1 == nil { 40 | templ_7745c5c3_Var1 = templ.NopComponent 41 | } 42 | ctx = templ.ClearChildren(ctx) 43 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(switchBaseClass, classes)} 44 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 45 | if templ_7745c5c3_Err != nil { 46 | return templ_7745c5c3_Err 47 | } 48 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 143 | if templ_7745c5c3_Err != nil { 144 | return templ_7745c5c3_Err 145 | } 146 | return templ_7745c5c3_Err 147 | }) 148 | } 149 | 150 | func switchThumb(disabled bool) templ.Component { 151 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 152 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 153 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 154 | return templ_7745c5c3_CtxErr 155 | } 156 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 157 | if !templ_7745c5c3_IsBuffer { 158 | defer func() { 159 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 160 | if templ_7745c5c3_Err == nil { 161 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 162 | } 163 | }() 164 | } 165 | ctx = templ.InitializeContext(ctx) 166 | templ_7745c5c3_Var7 := templ.GetChildren(ctx) 167 | if templ_7745c5c3_Var7 == nil { 168 | templ_7745c5c3_Var7 = templ.NopComponent 169 | } 170 | ctx = templ.ClearChildren(ctx) 171 | var templ_7745c5c3_Var8 = []any{switchThumbBaseClass} 172 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var8...) 173 | if templ_7745c5c3_Err != nil { 174 | return templ_7745c5c3_Err 175 | } 176 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 200 | if templ_7745c5c3_Err != nil { 201 | return templ_7745c5c3_Err 202 | } 203 | return templ_7745c5c3_Err 204 | }) 205 | } 206 | 207 | var _ = templruntime.GeneratedTemplate 208 | -------------------------------------------------------------------------------- /ui/table.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 4 | 5 | const ( 6 | tableBaseClass = "w-full caption-bottom text-sm" 7 | tableHeaderBaseClass = "[&_tr]:border-b" 8 | tableBodyBaseClass = "[&_tr:last-child]:border-0" 9 | tableFooterBaseClass = "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0" 10 | tableRowBaseClass = "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted" 11 | tableHeadBaseClass = "h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]" 12 | tableCellBaseClass = "p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]" 13 | tableCaptionBaseClass = "mt-4 text-sm text-muted-foreground" 14 | ) 15 | 16 | templ Table(classes string, attrs templ.Attributes) { 17 |
    18 | 22 | { children... } 23 |
    24 |
    25 | } 26 | 27 | templ TableHeader(classes string, attrs templ.Attributes) { 28 | 32 | { children... } 33 | 34 | } 35 | 36 | templ TableBody(classes string, attrs templ.Attributes) { 37 | 41 | { children... } 42 | 43 | } 44 | 45 | templ TableFooter(classes string, attrs templ.Attributes) { 46 | 50 | { children... } 51 | 52 | } 53 | 54 | templ TableRow(classes string, attrs templ.Attributes) { 55 | 59 | { children... } 60 | 61 | } 62 | 63 | templ TableHead(classes string, attrs templ.Attributes) { 64 | 68 | { children... } 69 | 70 | } 71 | 72 | templ TableCell(classes string, attrs templ.Attributes) { 73 | 77 | { children... } 78 | 79 | } 80 | 81 | templ TableCaption(classes string, attrs templ.Attributes) { 82 | 86 | { children... } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /ui/tabs.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import ( 4 | "fmt" 5 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 6 | ) 7 | 8 | const ( 9 | tabsListBaseClass = "inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground" 10 | tabsTriggerBaseClass = "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow" 11 | tabsContentBaseClass = "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2" 12 | ) 13 | 14 | templ Tabs(defaultValue, classes string, attrs templ.Attributes) { 15 |
    20 | { children... } 21 |
    22 | } 23 | 24 | templ TabsList(classes string, attrs templ.Attributes) { 25 |
    29 | { children... } 30 |
    31 | } 32 | 33 | templ TabsTrigger(value, classes string, attrs templ.Attributes) { 34 | 48 | } 49 | 50 | templ TabsContent(value, classes string, attrs templ.Attributes) { 51 |
    59 | { children... } 60 |
    61 | } 62 | -------------------------------------------------------------------------------- /ui/textarea.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 4 | 5 | const ( 6 | textareaBaseClass = "flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50" 7 | ) 8 | 9 | templ Textarea(name, classes string, attrs templ.Attributes) { 10 | 14 | } 15 | -------------------------------------------------------------------------------- /ui/textarea_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package ui 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 12 | 13 | const ( 14 | textareaBaseClass = "flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50" 15 | ) 16 | 17 | func Textarea(name, classes string, attrs templ.Attributes) templ.Component { 18 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 19 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 20 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 21 | return templ_7745c5c3_CtxErr 22 | } 23 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 24 | if !templ_7745c5c3_IsBuffer { 25 | defer func() { 26 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 27 | if templ_7745c5c3_Err == nil { 28 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 29 | } 30 | }() 31 | } 32 | ctx = templ.InitializeContext(ctx) 33 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 34 | if templ_7745c5c3_Var1 == nil { 35 | templ_7745c5c3_Var1 = templ.NopComponent 36 | } 37 | ctx = templ.ClearChildren(ctx) 38 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(textareaBaseClass, classes)} 39 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 40 | if templ_7745c5c3_Err != nil { 41 | return templ_7745c5c3_Err 42 | } 43 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 65 | if templ_7745c5c3_Err != nil { 66 | return templ_7745c5c3_Err 67 | } 68 | return templ_7745c5c3_Err 69 | }) 70 | } 71 | 72 | var _ = templruntime.GeneratedTemplate 73 | -------------------------------------------------------------------------------- /ui/toggle.templ: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import ( 4 | "fmt" 5 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 6 | ) 7 | 8 | const ( 9 | toggleBaseClass = "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground" 10 | ) 11 | 12 | type ToggleVariant int 13 | 14 | func (v ToggleVariant) Class() string { 15 | switch v { 16 | case ToggleVariantSecondary: 17 | return "border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground" 18 | default: 19 | return "bg-transparent" 20 | } 21 | } 22 | 23 | const ( 24 | ToggleVariantDefault ToggleVariant = iota 25 | ToggleVariantSecondary 26 | ) 27 | 28 | type ToggleSize int 29 | 30 | func (s ToggleSize) Class() string { 31 | switch s { 32 | case ToggleSizeSmall: 33 | return "h-8 px-2" 34 | case ToggleSizeLarge: 35 | return "h-10 px-3" 36 | default: 37 | return "h-9 px-3" 38 | } 39 | } 40 | 41 | const ( 42 | ToggleSizeDefault ToggleSize = iota 43 | ToggleSizeSmall 44 | ToggleSizeLarge 45 | ) 46 | 47 | templ Toggle(variant ToggleVariant, size ToggleSize, alpinePressed, classes string, attrs templ.Attributes) { 48 | 62 | } 63 | -------------------------------------------------------------------------------- /ui/toggle_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package ui 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | "fmt" 13 | "github.com/Oudwins/tailwind-merge-go/pkg/twmerge" 14 | ) 15 | 16 | const ( 17 | toggleBaseClass = "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground" 18 | ) 19 | 20 | type ToggleVariant int 21 | 22 | func (v ToggleVariant) Class() string { 23 | switch v { 24 | case ToggleVariantSecondary: 25 | return "border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground" 26 | default: 27 | return "bg-transparent" 28 | } 29 | } 30 | 31 | const ( 32 | ToggleVariantDefault ToggleVariant = iota 33 | ToggleVariantSecondary 34 | ) 35 | 36 | type ToggleSize int 37 | 38 | func (s ToggleSize) Class() string { 39 | switch s { 40 | case ToggleSizeSmall: 41 | return "h-8 px-2" 42 | case ToggleSizeLarge: 43 | return "h-10 px-3" 44 | default: 45 | return "h-9 px-3" 46 | } 47 | } 48 | 49 | const ( 50 | ToggleSizeDefault ToggleSize = iota 51 | ToggleSizeSmall 52 | ToggleSizeLarge 53 | ) 54 | 55 | func Toggle(variant ToggleVariant, size ToggleSize, alpinePressed, classes string, attrs templ.Attributes) templ.Component { 56 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 57 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 58 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 59 | return templ_7745c5c3_CtxErr 60 | } 61 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 62 | if !templ_7745c5c3_IsBuffer { 63 | defer func() { 64 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 65 | if templ_7745c5c3_Err == nil { 66 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 67 | } 68 | }() 69 | } 70 | ctx = templ.InitializeContext(ctx) 71 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 72 | if templ_7745c5c3_Var1 == nil { 73 | templ_7745c5c3_Var1 = templ.NopComponent 74 | } 75 | ctx = templ.ClearChildren(ctx) 76 | var templ_7745c5c3_Var2 = []any{twmerge.Merge(toggleBaseClass, variant.Class(), size.Class(), classes)} 77 | templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) 78 | if templ_7745c5c3_Err != nil { 79 | return templ_7745c5c3_Err 80 | } 81 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 160 | if templ_7745c5c3_Err != nil { 161 | return templ_7745c5c3_Err 162 | } 163 | return templ_7745c5c3_Err 164 | }) 165 | } 166 | 167 | var _ = templruntime.GeneratedTemplate 168 | -------------------------------------------------------------------------------- /ui/utils.go: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/a-h/templ" 7 | ) 8 | 9 | // boolAttr checks if an attribute exists and has a true value - `true` (bool) or `"true"` (string). 10 | func boolAttr(attr string, attrs templ.Attributes) bool { 11 | if v, ok := attrs[attr]; ok { 12 | if boolV, ok := v.(bool); ok && boolV { 13 | return true 14 | } else if stringV, ok := v.(string); ok && stringV == "true" { 15 | return true 16 | } 17 | } 18 | return false 19 | } 20 | 21 | func fmtBool(v bool) string { 22 | return fmt.Sprintf("%t", v) 23 | } 24 | --------------------------------------------------------------------------------