mirror of
https://github.com/axzilla/templui.git
synced 2025-02-22 01:33:15 +00:00
refactor: clean up unused CSS classes and improve toast handler structure
This commit is contained in:
parent
0bc679826c
commit
b8612c352c
@ -788,10 +788,6 @@ body {
|
|||||||
margin-left: 0.75rem;
|
margin-left: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ml-4 {
|
|
||||||
margin-left: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ml-auto {
|
.ml-auto {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
@ -1443,11 +1439,6 @@ body {
|
|||||||
background-color: hsl(var(--destructive) / var(--tw-bg-opacity, 1));
|
background-color: hsl(var(--destructive) / var(--tw-bg-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-gray-50 {
|
|
||||||
--tw-bg-opacity: 1;
|
|
||||||
background-color: rgb(249 250 251 / var(--tw-bg-opacity, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-gray-700 {
|
.bg-gray-700 {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(55 65 81 / var(--tw-bg-opacity, 1));
|
background-color: rgb(55 65 81 / var(--tw-bg-opacity, 1));
|
||||||
|
@ -13,21 +13,13 @@ import (
|
|||||||
"github.com/axzilla/templui/pkg/components"
|
"github.com/axzilla/templui/pkg/components"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HandleToastDemo(w http.ResponseWriter, r *http.Request) {
|
func toastDemoHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
duration, err := strconv.Atoi(r.FormValue("duration"))
|
duration, err := strconv.Atoi(r.FormValue("duration"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
duration = 0
|
duration = 0
|
||||||
}
|
}
|
||||||
fmt.Println("duration", duration)
|
|
||||||
fmt.Println("r.FormValue(\"message\")", r.FormValue("message"))
|
|
||||||
fmt.Println("r.FormValue(\"type\")", r.FormValue("type"))
|
|
||||||
fmt.Println("r.FormValue(\"position\")", r.FormValue("position"))
|
|
||||||
fmt.Println("r.FormValue(\"theme\")", r.FormValue("theme"))
|
|
||||||
fmt.Println("r.FormValue(\"size\")", r.FormValue("size"))
|
|
||||||
fmt.Println("r.FormValue(\"dismissible\")", r.FormValue("dismissible"))
|
|
||||||
fmt.Println("r.FormValue(\"icon\")", r.FormValue("icon"))
|
|
||||||
|
|
||||||
cfg := components.ToastProps{
|
toastProps := components.ToastProps{
|
||||||
Message: r.FormValue("message"),
|
Message: r.FormValue("message"),
|
||||||
Type: r.FormValue("type"),
|
Type: r.FormValue("type"),
|
||||||
Position: r.FormValue("position"),
|
Position: r.FormValue("position"),
|
||||||
@ -37,38 +29,7 @@ func HandleToastDemo(w http.ResponseWriter, r *http.Request) {
|
|||||||
Icon: r.FormValue("icon") == "on",
|
Icon: r.FormValue("icon") == "on",
|
||||||
}
|
}
|
||||||
|
|
||||||
components.Toast(cfg).Render(r.Context(), w)
|
components.Toast(toastProps).Render(r.Context(), w)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleCreateUser(w http.ResponseWriter, r *http.Request) {
|
|
||||||
email := r.FormValue("email")
|
|
||||||
|
|
||||||
// Validierung
|
|
||||||
if email == "" {
|
|
||||||
// Error Toast
|
|
||||||
components.Toast(components.ToastProps{
|
|
||||||
Message: "Email ist erforderlich",
|
|
||||||
Type: "error",
|
|
||||||
Position: "top-left",
|
|
||||||
Duration: 1000,
|
|
||||||
Dismissible: true,
|
|
||||||
Size: "md",
|
|
||||||
Icon: true,
|
|
||||||
}).Render(r.Context(), w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Erfolg Toast
|
|
||||||
components.Toast(components.ToastProps{
|
|
||||||
Message: "Benutzer erstellt",
|
|
||||||
Type: "success",
|
|
||||||
Position: "bottom-right",
|
|
||||||
Duration: 3000,
|
|
||||||
Dismissible: false,
|
|
||||||
Size: "sm",
|
|
||||||
Icon: true,
|
|
||||||
}).Render(r.Context(), w)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -108,8 +69,7 @@ func main() {
|
|||||||
mux.Handle("GET /docs/components/toast", templ.Handler(pages.Toast()))
|
mux.Handle("GET /docs/components/toast", templ.Handler(pages.Toast()))
|
||||||
mux.Handle("GET /docs/components/toggle", templ.Handler(pages.Toggle()))
|
mux.Handle("GET /docs/components/toggle", templ.Handler(pages.Toggle()))
|
||||||
// Showcase API
|
// Showcase API
|
||||||
mux.Handle("POST /users", http.HandlerFunc(HandleCreateUser))
|
mux.Handle("POST /docs/toast/demo", http.HandlerFunc(toastDemoHandler))
|
||||||
mux.Handle("POST /docs/toast/demo", http.HandlerFunc(HandleToastDemo))
|
|
||||||
|
|
||||||
fmt.Println("Server is running on http://localhost:8090")
|
fmt.Println("Server is running on http://localhost:8090")
|
||||||
http.ListenAndServe(":8090", wrappedMux)
|
http.ListenAndServe(":8090", wrappedMux)
|
||||||
|
@ -33,7 +33,6 @@ templ ExampleWrapper(p ExampleWrapperProps) {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateTabs erstellt die Tabs basierend auf den Props
|
|
||||||
func generateTabs(p ExampleWrapperProps) []components.Tab {
|
func generateTabs(p ExampleWrapperProps) []components.Tab {
|
||||||
tabs := []components.Tab{
|
tabs := []components.Tab{
|
||||||
{
|
{
|
||||||
@ -50,7 +49,6 @@ func generateTabs(p ExampleWrapperProps) []components.Tab {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Füge Component Tab nur hinzu wenn gewünscht
|
|
||||||
if p.ComponentCodeFile != "" {
|
if p.ComponentCodeFile != "" {
|
||||||
tabs = append(tabs, components.Tab{
|
tabs = append(tabs, components.Tab{
|
||||||
ID: "component",
|
ID: "component",
|
||||||
|
@ -1,27 +1,90 @@
|
|||||||
package pages
|
package pages
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/axzilla/templui/internals/ui/layouts"
|
"github.com/axzilla/templui/internals/ui/layouts"
|
||||||
"github.com/axzilla/templui/internals/ui/modules"
|
"github.com/axzilla/templui/internals/ui/modules"
|
||||||
"github.com/axzilla/templui/internals/ui/showcase"
|
"github.com/axzilla/templui/internals/ui/showcase"
|
||||||
|
"github.com/axzilla/templui/pkg/components"
|
||||||
)
|
)
|
||||||
|
|
||||||
templ Toast() {
|
templ Toast() {
|
||||||
@layouts.DocsLayout() {
|
@layouts.DocsLayout() {
|
||||||
@modules.PageWrapper(modules.PageWrapperProps{
|
@modules.PageWrapper(modules.PageWrapperProps{
|
||||||
Name: "Toast",
|
Name: "Toast",
|
||||||
Description: templ.Raw("Flexible Toast component for notifications and feedback."),
|
Description: templ.Raw("Flexible toast component for notifications and feedback."),
|
||||||
}) {
|
}) {
|
||||||
// @modules.ExampleWrapper(modules.ExampleWrapperProps{
|
|
||||||
// ShowcaseFile: showcase.Toast(),
|
|
||||||
// PreviewCodeFile: "toast.templ",
|
|
||||||
// ComponentCodeFile: "toast.templ",
|
|
||||||
// })
|
|
||||||
@modules.ExampleWrapper(modules.ExampleWrapperProps{
|
@modules.ExampleWrapper(modules.ExampleWrapperProps{
|
||||||
ShowcaseFile: showcase.ToastAdvanced(),
|
ShowcaseFile: showcase.Toast(),
|
||||||
PreviewCodeFile: "toast_advancded.templ",
|
PreviewCodeFile: "toast.templ",
|
||||||
ComponentCodeFile: "toast.templ",
|
ComponentCodeFile: "toast.templ",
|
||||||
})
|
})
|
||||||
|
@UsageExamples()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
templ UsageExamples() {
|
||||||
|
@components.Tabs(components.TabsProps{
|
||||||
|
Tabs: []components.Tab{
|
||||||
|
{
|
||||||
|
ID: "with-htmx",
|
||||||
|
Title: "With HTMX",
|
||||||
|
Content: withHtmx(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "full-page-form",
|
||||||
|
Title: "Full Page Form",
|
||||||
|
Content: fullPageForm(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TabsContainerClass: "w-full",
|
||||||
|
ContentContainerClass: "w-full",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var withHtmxCode = fmt.Sprintf(`// Template
|
||||||
|
%s UserForm() {
|
||||||
|
<form hx-post="/save" hx-target="#toast">
|
||||||
|
<input name="email" />
|
||||||
|
</form>
|
||||||
|
<div id="toast"></div>
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handler
|
||||||
|
func Save(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if err != nil {
|
||||||
|
components.Toast(components.ToastProps{
|
||||||
|
Message: err.Error(),
|
||||||
|
Type: "error",
|
||||||
|
}).Render(r.Context(), w)
|
||||||
|
}
|
||||||
|
}`, "templ")
|
||||||
|
|
||||||
|
templ withHtmx() {
|
||||||
|
@modules.CodeSnippet(withHtmxCode, "go")
|
||||||
|
}
|
||||||
|
|
||||||
|
var fullPageFormCode = fmt.Sprintf(`// Template
|
||||||
|
%s UserForm(error string) {
|
||||||
|
if error != "" {
|
||||||
|
@components.Toast(components.ToastProps{
|
||||||
|
Message: error,
|
||||||
|
Type: "error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
<form method="POST">
|
||||||
|
<input name="email"/>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handler
|
||||||
|
func Save(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if err != nil {
|
||||||
|
UserForm(err.Error()).Render(r.Context(), w)
|
||||||
|
}
|
||||||
|
}`, "templ")
|
||||||
|
|
||||||
|
templ fullPageForm() {
|
||||||
|
@modules.CodeSnippet(string(fullPageFormCode), "go")
|
||||||
|
}
|
||||||
|
@ -1,25 +1,104 @@
|
|||||||
package showcase
|
package showcase
|
||||||
|
|
||||||
|
import "github.com/axzilla/templui/pkg/components"
|
||||||
|
|
||||||
templ Toast() {
|
templ Toast() {
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="w-full max-w-4xl mx-auto p-8">
|
||||||
<div>
|
<section class="mb-12">
|
||||||
<form
|
@components.Card(components.CardProps{}) {
|
||||||
hx-post="/users"
|
@components.CardContent() {
|
||||||
hx-target="#toast-container"
|
<form
|
||||||
class="space-y-4"
|
class="flex flex-col gap-2"
|
||||||
>
|
hx-post="/docs/toast/demo"
|
||||||
<div>
|
hx-trigger="submit"
|
||||||
<label for="email">Email</label>
|
hx-target="#toast-container"
|
||||||
<input
|
>
|
||||||
type="email"
|
// Message
|
||||||
name="email"
|
@components.FormItem(components.FormItemProps{}) {
|
||||||
id="email"
|
@components.Label(components.LabelProps{Text: "Message"})
|
||||||
class="w-full rounded-lg border"
|
@components.Input(components.InputProps{
|
||||||
/>
|
Value: "Test Notification",
|
||||||
</div>
|
Name: "message",
|
||||||
<button type="submit">Speichern</button>
|
})
|
||||||
</form>
|
}
|
||||||
<div id="toast-container"></div>
|
// Type
|
||||||
</div>
|
@components.FormItem(components.FormItemProps{}) {
|
||||||
|
@components.Label(components.LabelProps{Text: "Type"})
|
||||||
|
@components.Select(components.SelectProps{
|
||||||
|
Name: "type",
|
||||||
|
Options: []components.SelectOption{
|
||||||
|
{Value: "default", Label: "Default"},
|
||||||
|
{Value: "success", Label: "Success"},
|
||||||
|
{Value: "error", Label: "Error"},
|
||||||
|
{Value: "warning", Label: "Warning"},
|
||||||
|
{Value: "info", Label: "Info"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// Position
|
||||||
|
@components.FormItem(components.FormItemProps{}) {
|
||||||
|
@components.Label(components.LabelProps{Text: "Position"})
|
||||||
|
@components.Select(components.SelectProps{
|
||||||
|
Name: "position",
|
||||||
|
Options: []components.SelectOption{
|
||||||
|
{Value: "top-right", Label: "Top Right"},
|
||||||
|
{Value: "top-left", Label: "Top Left"},
|
||||||
|
{Value: "top-center", Label: "Top Center"},
|
||||||
|
{Value: "bottom-right", Label: "Bottom Right", Selected: true},
|
||||||
|
{Value: "bottom-left", Label: "Bottom Left"},
|
||||||
|
{Value: "bottom-center", Label: "Bottom Center"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// Duration
|
||||||
|
@components.FormItem(components.FormItemProps{}) {
|
||||||
|
@components.Label(components.LabelProps{Text: "Duration (ms)"})
|
||||||
|
@components.Input(components.InputProps{
|
||||||
|
Type: "number",
|
||||||
|
Name: "duration",
|
||||||
|
Value: "3000",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// Size
|
||||||
|
@components.FormItem(components.FormItemProps{}) {
|
||||||
|
@components.Label(components.LabelProps{Text: "Size"})
|
||||||
|
@components.Select(components.SelectProps{
|
||||||
|
Name: "size",
|
||||||
|
Options: []components.SelectOption{
|
||||||
|
{Value: "sm", Label: "Small"},
|
||||||
|
{Value: "md", Label: "Medium"},
|
||||||
|
{Value: "lg", Label: "Large"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// Options
|
||||||
|
@components.FormItem(components.FormItemProps{}) {
|
||||||
|
@components.Label(components.LabelProps{Text: "Options"})
|
||||||
|
@components.FormItemFlex(components.FormItemProps{}) {
|
||||||
|
@components.Toggle(components.ToggleProps{
|
||||||
|
Name: "dismissible",
|
||||||
|
Checked: true,
|
||||||
|
})
|
||||||
|
@components.Label(components.LabelProps{Text: "Dismissible"})
|
||||||
|
}
|
||||||
|
@components.FormItemFlex(components.FormItemProps{}) {
|
||||||
|
@components.Toggle(components.ToggleProps{
|
||||||
|
Name: "icon",
|
||||||
|
Checked: true,
|
||||||
|
})
|
||||||
|
@components.Label(components.LabelProps{Text: "Show Icon"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Submit
|
||||||
|
@components.Button(components.ButtonProps{
|
||||||
|
Text: "Show Toast",
|
||||||
|
Type: "submit",
|
||||||
|
Class: "w-full",
|
||||||
|
})
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</section>
|
||||||
|
<div id="toast-container"></div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -1,139 +0,0 @@
|
|||||||
package showcase
|
|
||||||
|
|
||||||
import "github.com/axzilla/templui/pkg/components"
|
|
||||||
|
|
||||||
templ ToastAdvanced() {
|
|
||||||
<div class="max-w-4xl mx-auto p-8">
|
|
||||||
<section class="mb-12">
|
|
||||||
@components.Card(components.CardProps{}) {
|
|
||||||
@components.CardContent() {
|
|
||||||
<form
|
|
||||||
class="flex flex-col gap-2"
|
|
||||||
hx-post="/docs/toast/demo"
|
|
||||||
hx-trigger="change, submit"
|
|
||||||
hx-target="#toast-containerx"
|
|
||||||
>
|
|
||||||
// Message
|
|
||||||
@components.FormItem(components.FormItemProps{}) {
|
|
||||||
@components.Label(components.LabelProps{Text: "Message"})
|
|
||||||
@components.Input(components.InputProps{
|
|
||||||
Value: "Test Notification",
|
|
||||||
Name: "message",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// Type
|
|
||||||
@components.FormItem(components.FormItemProps{}) {
|
|
||||||
@components.Label(components.LabelProps{Text: "Type"})
|
|
||||||
@components.Select(components.SelectProps{
|
|
||||||
Name: "type",
|
|
||||||
Options: []components.SelectOption{
|
|
||||||
{Value: "default", Label: "Default"},
|
|
||||||
{Value: "success", Label: "Success"},
|
|
||||||
{Value: "error", Label: "Error"},
|
|
||||||
{Value: "warning", Label: "Warning"},
|
|
||||||
{Value: "info", Label: "Info"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// Position
|
|
||||||
@components.FormItem(components.FormItemProps{}) {
|
|
||||||
@components.Label(components.LabelProps{Text: "Position"})
|
|
||||||
@components.Select(components.SelectProps{
|
|
||||||
Name: "position",
|
|
||||||
Options: []components.SelectOption{
|
|
||||||
{Value: "top-right", Label: "Top Right"},
|
|
||||||
{Value: "top-left", Label: "Top Left"},
|
|
||||||
{Value: "top-center", Label: "Top Center"},
|
|
||||||
{Value: "bottom-right", Label: "Bottom Right"},
|
|
||||||
{Value: "bottom-left", Label: "Bottom Left"},
|
|
||||||
{Value: "bottom-center", Label: "Bottom Center"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// Duration
|
|
||||||
@components.FormItem(components.FormItemProps{}) {
|
|
||||||
@components.Label(components.LabelProps{Text: "Duration (ms)"})
|
|
||||||
@components.Input(components.InputProps{
|
|
||||||
Type: "number",
|
|
||||||
Name: "duration",
|
|
||||||
Value: "3000",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// Size
|
|
||||||
@components.FormItem(components.FormItemProps{}) {
|
|
||||||
@components.Label(components.LabelProps{Text: "Size"})
|
|
||||||
@components.Select(components.SelectProps{
|
|
||||||
Name: "size",
|
|
||||||
Options: []components.SelectOption{
|
|
||||||
{Value: "sm", Label: "Small"},
|
|
||||||
{Value: "md", Label: "Medium"},
|
|
||||||
{Value: "lg", Label: "Large"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// Options
|
|
||||||
@components.FormItem(components.FormItemProps{}) {
|
|
||||||
@components.Label(components.LabelProps{Text: "Options"})
|
|
||||||
@components.FormItemFlex(components.FormItemProps{}) {
|
|
||||||
@components.Toggle(components.ToggleProps{
|
|
||||||
Name: "dismissible",
|
|
||||||
Checked: true,
|
|
||||||
})
|
|
||||||
@components.Label(components.LabelProps{Text: "Dismissible"})
|
|
||||||
}
|
|
||||||
@components.FormItemFlex(components.FormItemProps{}) {
|
|
||||||
@components.Toggle(components.ToggleProps{
|
|
||||||
Name: "icon",
|
|
||||||
Checked: true,
|
|
||||||
})
|
|
||||||
@components.Label(components.LabelProps{Text: "Show Icon"})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@components.Button(components.ButtonProps{
|
|
||||||
Text: "Show Toast",
|
|
||||||
Type: "submit",
|
|
||||||
Class: "w-full",
|
|
||||||
})
|
|
||||||
</form>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</section>
|
|
||||||
<div id="toast-containerx"></div>
|
|
||||||
// Code Examples
|
|
||||||
<section>
|
|
||||||
<h2 class="text-xl font-semibold mb-4">Usage Examples</h2>
|
|
||||||
<div class="space-y-4">
|
|
||||||
<div class="p-4 bg-gray-50 rounded-lg">
|
|
||||||
<h3 class="font-medium mb-2">Basic Usage</h3>
|
|
||||||
<pre class="text-sm">
|
|
||||||
{ `// In your handler
|
|
||||||
components.Toast(types.ToastConfig{
|
|
||||||
Message: "Nachricht",
|
|
||||||
Type: "success",
|
|
||||||
Position: "top-right",
|
|
||||||
Duration: 3000,
|
|
||||||
}).Render(ctx, w)` }
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
<div class="p-4 bg-gray-50 rounded-lg">
|
|
||||||
<h3 class="font-medium mb-2">With HTMX</h3>
|
|
||||||
<pre class="text-sm">
|
|
||||||
{ `// Template
|
|
||||||
<form hx-post="/save" hx-target="#toast-container">
|
|
||||||
...
|
|
||||||
</form>
|
|
||||||
<div id="toast-container"></div>
|
|
||||||
|
|
||||||
// Handler
|
|
||||||
if err != nil {
|
|
||||||
return components.Toast(types.ToastConfig{
|
|
||||||
Message: err.Error(),
|
|
||||||
Type: "error",
|
|
||||||
}).Render(ctx, w)
|
|
||||||
}` }
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
}
|
|
@ -6,26 +6,26 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ToastProps struct {
|
type ToastProps struct {
|
||||||
Message string // Die Nachricht
|
Message string // Message to display
|
||||||
Type string // success, error, warning, info, default
|
Type string // Type of the toast (default, success, error, warning, info)
|
||||||
Position string // top-right, top-left, top-center, bottom-right, bottom-left, bottom-center
|
Position string // Position of the toast (top-right, top-left, top-center, bottom-right, bottom-left, bottom-center)
|
||||||
Duration int // Millisekunden, 0 = permanent
|
Duration int // Duration in milliseconds
|
||||||
Dismissible bool // Kann manuell geschlossen werden
|
Dismissible bool // Show dismiss button
|
||||||
Size string // sm, md, lg
|
Size string // Size of the toast (sm, md, lg)
|
||||||
Icon bool // Icon anzeigen/verstecken
|
Icon bool // Show icon
|
||||||
HTML string // Custom HTML Content
|
|
||||||
}
|
}
|
||||||
|
|
||||||
templ Toast(cfg ToastProps) {
|
// Flexible toast component for notifications and feedback.
|
||||||
|
templ Toast(props ToastProps) {
|
||||||
<div
|
<div
|
||||||
x-data={ `{
|
x-data={ `{
|
||||||
show: true,
|
show: true,
|
||||||
message: '` + cfg.Message + `',
|
message: '` + props.Message + `',
|
||||||
type: '` + cfg.Type + `',
|
type: '` + props.Type + `',
|
||||||
position: '` + cfg.Position + `',
|
position: '` + props.Position + `',
|
||||||
duration: ` + fmt.Sprint(cfg.Duration) + `,
|
duration: ` + fmt.Sprint(props.Duration) + `,
|
||||||
dismissible: ` + fmt.Sprint(cfg.Dismissible) + `,
|
dismissible: ` + fmt.Sprint(props.Dismissible) + `,
|
||||||
size: '` + cfg.Size + `'
|
size: '` + props.Size + `'
|
||||||
}` }
|
}` }
|
||||||
x-init="if(duration > 0) setTimeout(() => show = false, duration)"
|
x-init="if(duration > 0) setTimeout(() => show = false, duration)"
|
||||||
x-show="show"
|
x-show="show"
|
||||||
@ -36,7 +36,7 @@ templ Toast(cfg ToastProps) {
|
|||||||
x-transition:leave-start="opacity-100 translate-y-0"
|
x-transition:leave-start="opacity-100 translate-y-0"
|
||||||
x-transition:leave-end="opacity-0 translate-y-4"
|
x-transition:leave-end="opacity-0 translate-y-4"
|
||||||
@click="if(dismissible) show = false"
|
@click="if(dismissible) show = false"
|
||||||
class="fixed pointer-events-auto"
|
class="z-50 fixed pointer-events-auto"
|
||||||
:class="{
|
:class="{
|
||||||
// Position
|
// Position
|
||||||
'top-4 right-4': position === 'top-right',
|
'top-4 right-4': position === 'top-right',
|
||||||
@ -51,43 +51,34 @@ templ Toast(cfg ToastProps) {
|
|||||||
'w-[30rem]': size === 'lg'
|
'w-[30rem]': size === 'lg'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
if cfg.HTML != "" {
|
<div
|
||||||
<div
|
class="bg-primary-foreground rounded-lg shadow-sm border p-4 flex items-center justify-center"
|
||||||
x-html="message"
|
>
|
||||||
class="rounded-lg shadow-lg"
|
if props.Icon {
|
||||||
></div>
|
if props.Type == "success" {
|
||||||
} else {
|
@icons.CircleCheck(icons.IconProps{Size: "18", Class: "text-green-500 mr-3"})
|
||||||
// Default Toast
|
|
||||||
<div
|
|
||||||
class="bg-primary-foreground rounded-lg shadow-sm border p-4 flex items-center justify-center"
|
|
||||||
>
|
|
||||||
if cfg.Icon {
|
|
||||||
// Icons für verschiedene Types
|
|
||||||
if cfg.Type == "success" {
|
|
||||||
@icons.CircleCheck(icons.IconProps{Size: "18", Class: "text-green-500 mr-3"})
|
|
||||||
}
|
|
||||||
if cfg.Type == "error" {
|
|
||||||
@icons.CircleX(icons.IconProps{Size: "18", Class: "text-red-500 mr-3"})
|
|
||||||
}
|
|
||||||
if cfg.Type == "warning" {
|
|
||||||
@icons.TriangleAlert(icons.IconProps{Size: "18", Class: "text-yellow-500 mr-3"})
|
|
||||||
}
|
|
||||||
if cfg.Type == "info" {
|
|
||||||
@icons.Info(icons.IconProps{Size: "18", Class: "text-blue-500 mr-3"})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
<div class="flex-1" x-text="message"></div>
|
if props.Type == "error" {
|
||||||
if cfg.Dismissible {
|
@icons.CircleX(icons.IconProps{Size: "18", Class: "text-red-500 mr-3"})
|
||||||
<button
|
|
||||||
@click.stop="show = false"
|
|
||||||
>
|
|
||||||
@icons.X(icons.IconProps{
|
|
||||||
Size: "18",
|
|
||||||
Class: "ml-4 flex-shrink-0 opacity-75 hover:opacity-100",
|
|
||||||
})
|
|
||||||
</button>
|
|
||||||
}
|
}
|
||||||
</div>
|
if props.Type == "warning" {
|
||||||
}
|
@icons.TriangleAlert(icons.IconProps{Size: "18", Class: "text-yellow-500 mr-3"})
|
||||||
|
}
|
||||||
|
if props.Type == "info" {
|
||||||
|
@icons.Info(icons.IconProps{Size: "18", Class: "text-blue-500 mr-3"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<div class="flex-1" x-text="message"></div>
|
||||||
|
if props.Dismissible {
|
||||||
|
<button
|
||||||
|
@click.stop="show = false"
|
||||||
|
>
|
||||||
|
@icons.X(icons.IconProps{
|
||||||
|
Size: "18",
|
||||||
|
Class: "opacity-75 hover:opacity-100",
|
||||||
|
})
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -14,17 +14,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ToastProps struct {
|
type ToastProps struct {
|
||||||
Message string // Die Nachricht
|
Message string // Message to display
|
||||||
Type string // success, error, warning, info, default
|
Type string // Type of the toast (default, success, error, warning, info)
|
||||||
Position string // top-right, top-left, top-center, bottom-right, bottom-left, bottom-center
|
Position string // Position of the toast (top-right, top-left, top-center, bottom-right, bottom-left, bottom-center)
|
||||||
Duration int // Millisekunden, 0 = permanent
|
Duration int // Duration in milliseconds
|
||||||
Dismissible bool // Kann manuell geschlossen werden
|
Dismissible bool // Show dismiss button
|
||||||
Size string // sm, md, lg
|
Size string // Size of the toast (sm, md, lg)
|
||||||
Icon bool // Icon anzeigen/verstecken
|
Icon bool // Show icon
|
||||||
HTML string // Custom HTML Content
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Toast(cfg ToastProps) templ.Component {
|
// Flexible toast component for notifications and feedback.
|
||||||
|
func Toast(props ToastProps) templ.Component {
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
@ -52,12 +52,12 @@ func Toast(cfg ToastProps) templ.Component {
|
|||||||
var templ_7745c5c3_Var2 string
|
var templ_7745c5c3_Var2 string
|
||||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(`{
|
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(`{
|
||||||
show: true,
|
show: true,
|
||||||
message: '` + cfg.Message + `',
|
message: '` + props.Message + `',
|
||||||
type: '` + cfg.Type + `',
|
type: '` + props.Type + `',
|
||||||
position: '` + cfg.Position + `',
|
position: '` + props.Position + `',
|
||||||
duration: ` + fmt.Sprint(cfg.Duration) + `,
|
duration: ` + fmt.Sprint(props.Duration) + `,
|
||||||
dismissible: ` + fmt.Sprint(cfg.Dismissible) + `,
|
dismissible: ` + fmt.Sprint(props.Dismissible) + `,
|
||||||
size: '` + cfg.Size + `'
|
size: '` + props.Size + `'
|
||||||
}`)
|
}`)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/toast.templ`, Line: 29, Col: 10}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/toast.templ`, Line: 29, Col: 10}
|
||||||
@ -66,89 +66,70 @@ func Toast(cfg ToastProps) templ.Component {
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" x-init=\"if(duration > 0) setTimeout(() => show = false, duration)\" x-show=\"show\" x-transition:enter=\"transition ease-out duration-300\" x-transition:enter-start=\"opacity-0 translate-y-4\" x-transition:enter-end=\"opacity-100 translate-y-0\" x-transition:leave=\"transition ease-in duration-200\" x-transition:leave-start=\"opacity-100 translate-y-0\" x-transition:leave-end=\"opacity-0 translate-y-4\" @click=\"if(dismissible) show = false\" class=\"fixed pointer-events-auto\" :class=\"{\n // Position\n 'top-4 right-4': position === 'top-right',\n 'top-4 left-4': position === 'top-left',\n 'top-4 left-1/2 -translate-x-1/2': position === 'top-center',\n 'bottom-4 right-4': position === 'bottom-right',\n 'bottom-4 left-4': position === 'bottom-left',\n 'bottom-4 left-1/2 -translate-x-1/2': position === 'bottom-center',\n // Size\n 'w-72': size === 'sm',\n 'w-96': size === 'md',\n 'w-[30rem]': size === 'lg'\n }\">")
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" x-init=\"if(duration > 0) setTimeout(() => show = false, duration)\" x-show=\"show\" x-transition:enter=\"transition ease-out duration-300\" x-transition:enter-start=\"opacity-0 translate-y-4\" x-transition:enter-end=\"opacity-100 translate-y-0\" x-transition:leave=\"transition ease-in duration-200\" x-transition:leave-start=\"opacity-100 translate-y-0\" x-transition:leave-end=\"opacity-0 translate-y-4\" @click=\"if(dismissible) show = false\" class=\"z-50 fixed pointer-events-auto\" :class=\"{\n // Position\n 'top-4 right-4': position === 'top-right',\n 'top-4 left-4': position === 'top-left',\n 'top-4 left-1/2 -translate-x-1/2': position === 'top-center',\n 'bottom-4 right-4': position === 'bottom-right',\n 'bottom-4 left-4': position === 'bottom-left',\n 'bottom-4 left-1/2 -translate-x-1/2': position === 'bottom-center',\n // Size\n 'w-72': size === 'sm',\n 'w-96': size === 'md',\n 'w-[30rem]': size === 'lg'\n }\"><div class=\"bg-primary-foreground rounded-lg shadow-sm border p-4 flex items-center justify-center\">")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if cfg.HTML != "" {
|
if props.Icon {
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div x-html=\"message\" class=\"rounded-lg shadow-lg\"></div>")
|
if props.Type == "success" {
|
||||||
|
templ_7745c5c3_Err = icons.CircleCheck(icons.IconProps{Size: "18", Class: "text-green-500 mr-3"}).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
} else {
|
if props.Type == "error" {
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"bg-primary-foreground rounded-lg shadow-sm border p-4 flex items-center justify-center\">")
|
templ_7745c5c3_Err = icons.CircleX(icons.IconProps{Size: "18", Class: "text-red-500 mr-3"}).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if cfg.Icon {
|
if props.Type == "warning" {
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
templ_7745c5c3_Err = icons.TriangleAlert(icons.IconProps{Size: "18", Class: "text-yellow-500 mr-3"}).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if cfg.Type == "success" {
|
|
||||||
templ_7745c5c3_Err = icons.CircleCheck(icons.IconProps{Size: "18", Class: "text-green-500 mr-3"}).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if cfg.Type == "error" {
|
|
||||||
templ_7745c5c3_Err = icons.CircleX(icons.IconProps{Size: "18", Class: "text-red-500 mr-3"}).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if cfg.Type == "warning" {
|
|
||||||
templ_7745c5c3_Err = icons.TriangleAlert(icons.IconProps{Size: "18", Class: "text-yellow-500 mr-3"}).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if cfg.Type == "info" {
|
|
||||||
templ_7745c5c3_Err = icons.Info(icons.IconProps{Size: "18", Class: "text-blue-500 mr-3"}).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex-1\" x-text=\"message\"></div>")
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if cfg.Dismissible {
|
if props.Type == "info" {
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<button @click.stop=\"show = false\">")
|
templ_7745c5c3_Err = icons.Info(icons.IconProps{Size: "18", Class: "text-blue-500 mr-3"}).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = icons.X(icons.IconProps{
|
|
||||||
Size: "18",
|
|
||||||
Class: "ml-4 flex-shrink-0 opacity-75 hover:opacity-100",
|
|
||||||
}).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</button>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex-1\" x-text=\"message\"></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if props.Dismissible {
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<button @click.stop=\"show = false\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = icons.X(icons.IconProps{
|
||||||
|
Size: "18",
|
||||||
|
Class: "opacity-75 hover:opacity-100",
|
||||||
|
}).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</button>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user