1
0
mirror of https://github.com/axzilla/templui.git synced 2025-02-21 01:32:45 +00:00

feat: add alert component

This commit is contained in:
“axzilla” 2024-10-07 11:57:03 +02:00
parent b17507a717
commit a319540f30
7 changed files with 302 additions and 109 deletions

View File

@ -3,6 +3,7 @@
## 2024-10-07
- Added: Input component
- Added: Alert component
- Added: Accordion component
- Added: Datepicker component
- Changed: Add button type prop

View File

@ -711,6 +711,10 @@ body {
margin-right: auto;
}
.mb-1 {
margin-bottom: 0.25rem;
}
.mb-12 {
margin-bottom: 3rem;
}
@ -751,6 +755,10 @@ body {
margin-right: 0.5rem;
}
.mt-12 {
margin-top: 3rem;
}
.mt-2 {
margin-top: 0.5rem;
}
@ -759,14 +767,6 @@ body {
margin-top: 1rem;
}
.mb-1 {
margin-bottom: 0.25rem;
}
.mt-12 {
margin-top: 3rem;
}
.block {
display: block;
}
@ -815,6 +815,10 @@ body {
height: 1.5rem;
}
.h-7 {
height: 1.75rem;
}
.h-8 {
height: 2rem;
}
@ -831,10 +835,6 @@ body {
height: 100%;
}
.h-7 {
height: 1.75rem;
}
.\!max-h-\[501px\] {
max-height: 501px !important;
}
@ -871,14 +871,6 @@ body {
width: 16rem;
}
.w-\[350px\] {
width: 350px;
}
.w-full {
width: 100%;
}
.w-7 {
width: 1.75rem;
}
@ -887,6 +879,14 @@ body {
width: 17rem;
}
.w-\[350px\] {
width: 350px;
}
.w-full {
width: 100%;
}
.max-w-3xl {
max-width: 48rem;
}
@ -895,6 +895,10 @@ body {
max-width: 80rem;
}
.max-w-lg {
max-width: 32rem;
}
.max-w-md {
max-width: 28rem;
}
@ -907,10 +911,6 @@ body {
max-width: 20rem;
}
.max-w-lg {
max-width: 32rem;
}
.flex-1 {
flex: 1 1 0%;
}
@ -1017,10 +1017,6 @@ body {
gap: 1rem;
}
.gap-1 {
gap: 0.25rem;
}
.space-x-2 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.5rem * var(--tw-space-x-reverse));
@ -1102,6 +1098,10 @@ body {
border-radius: 0.25rem;
}
.rounded-full {
border-radius: 9999px;
}
.rounded-lg {
border-radius: var(--radius);
}
@ -1110,10 +1110,6 @@ body {
border-radius: calc(var(--radius) - 2px);
}
.rounded-full {
border-radius: 9999px;
}
.border {
border-width: 1px;
}
@ -1139,6 +1135,10 @@ body {
border-color: hsl(var(--border) / var(--tw-border-opacity));
}
.border-destructive\/50 {
border-color: hsl(var(--destructive) / 0.5);
}
.border-input {
--tw-border-opacity: 1;
border-color: hsl(var(--input) / var(--tw-border-opacity));
@ -1152,6 +1152,11 @@ body {
border-color: transparent;
}
.border-destructive {
--tw-border-opacity: 1;
border-color: hsl(var(--destructive) / var(--tw-border-opacity));
}
.bg-background {
--tw-bg-opacity: 1;
background-color: hsl(var(--background) / var(--tw-bg-opacity));
@ -1181,6 +1186,16 @@ body {
background-color: hsl(var(--muted) / var(--tw-bg-opacity));
}
.bg-neutral-200 {
--tw-bg-opacity: 1;
background-color: rgb(229 229 229 / var(--tw-bg-opacity));
}
.bg-neutral-800 {
--tw-bg-opacity: 1;
background-color: rgb(38 38 38 / var(--tw-bg-opacity));
}
.bg-primary {
--tw-bg-opacity: 1;
background-color: hsl(var(--primary) / var(--tw-bg-opacity));
@ -1196,31 +1211,6 @@ body {
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.bg-blue-100 {
--tw-bg-opacity: 1;
background-color: rgb(219 234 254 / var(--tw-bg-opacity));
}
.bg-blue-500 {
--tw-bg-opacity: 1;
background-color: rgb(59 130 246 / var(--tw-bg-opacity));
}
.bg-red-500 {
--tw-bg-opacity: 1;
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
}
.bg-neutral-200 {
--tw-bg-opacity: 1;
background-color: rgb(229 229 229 / var(--tw-bg-opacity));
}
.bg-neutral-800 {
--tw-bg-opacity: 1;
background-color: rgb(38 38 38 / var(--tw-bg-opacity));
}
.bg-opacity-75 {
--tw-bg-opacity: 0.75;
}
@ -1272,6 +1262,11 @@ body {
padding: 1.5rem;
}
.px-0\.5 {
padding-left: 0.125rem;
padding-right: 0.125rem;
}
.px-2 {
padding-left: 0.5rem;
padding-right: 0.5rem;
@ -1337,11 +1332,6 @@ body {
padding-bottom: 2rem;
}
.px-0\.5 {
padding-left: 0.125rem;
padding-right: 0.125rem;
}
.pb-4 {
padding-bottom: 1rem;
}
@ -1418,14 +1408,14 @@ body {
font-weight: 500;
}
.font-semibold {
font-weight: 600;
}
.font-normal {
font-weight: 400;
}
.font-semibold {
font-weight: 600;
}
.uppercase {
text-transform: uppercase;
}
@ -1448,6 +1438,11 @@ body {
color: hsl(var(--card-foreground) / var(--tw-text-opacity));
}
.text-destructive {
--tw-text-opacity: 1;
color: hsl(var(--destructive) / var(--tw-text-opacity));
}
.text-destructive-foreground {
--tw-text-opacity: 1;
color: hsl(var(--destructive-foreground) / var(--tw-text-opacity));
@ -1473,6 +1468,11 @@ body {
color: rgb(55 65 81 / var(--tw-text-opacity));
}
.text-gray-800 {
--tw-text-opacity: 1;
color: rgb(31 41 55 / var(--tw-text-opacity));
}
.text-gray-900 {
--tw-text-opacity: 1;
color: rgb(17 24 39 / var(--tw-text-opacity));
@ -1483,6 +1483,11 @@ body {
color: hsl(var(--muted-foreground) / var(--tw-text-opacity));
}
.text-neutral-400 {
--tw-text-opacity: 1;
color: rgb(163 163 163 / var(--tw-text-opacity));
}
.text-primary {
--tw-text-opacity: 1;
color: hsl(var(--primary) / var(--tw-text-opacity));
@ -1503,16 +1508,6 @@ body {
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.text-gray-800 {
--tw-text-opacity: 1;
color: rgb(31 41 55 / var(--tw-text-opacity));
}
.text-neutral-400 {
--tw-text-opacity: 1;
color: rgb(163 163 163 / var(--tw-text-opacity));
}
.underline {
text-decoration-line: underline;
}
@ -1534,6 +1529,12 @@ body {
opacity: 1;
}
.shadow {
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.shadow-lg {
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
@ -1546,12 +1547,6 @@ body {
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.shadow {
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.outline {
outline-style: solid;
}
@ -1592,6 +1587,10 @@ body {
transition-duration: 150ms;
}
.duration-100 {
transition-duration: 100ms;
}
.duration-200 {
transition-duration: 200ms;
}
@ -1600,22 +1599,18 @@ body {
transition-duration: 300ms;
}
.duration-100 {
transition-duration: 100ms;
}
.ease-in {
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
}
.ease-out {
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
}
.ease-in-out {
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
.ease-out {
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
}
.\[mask-image\:linear-gradient\(180deg\2c white\2c rgba\(255\2c 255\2c 255\2c 0\)\)\] {
-webkit-mask-image: linear-gradient(180deg,white,rgba(255,255,255,0));
mask-image: linear-gradient(180deg,white,rgba(255,255,255,0));
@ -1672,6 +1667,11 @@ body {
background-color: rgb(75 85 99 / var(--tw-bg-opacity));
}
.hover\:bg-neutral-200:hover {
--tw-bg-opacity: 1;
background-color: rgb(229 229 229 / var(--tw-bg-opacity));
}
.hover\:bg-primary\/90:hover {
background-color: hsl(var(--primary) / 0.9);
}
@ -1680,16 +1680,6 @@ body {
background-color: hsl(var(--secondary) / 0.8);
}
.hover\:bg-blue-100:hover {
--tw-bg-opacity: 1;
background-color: rgb(219 234 254 / var(--tw-bg-opacity));
}
.hover\:bg-neutral-200:hover {
--tw-bg-opacity: 1;
background-color: rgb(229 229 229 / var(--tw-bg-opacity));
}
.hover\:bg-opacity-75:hover {
--tw-bg-opacity: 0.75;
}
@ -1709,15 +1699,15 @@ body {
color: rgb(107 114 128 / var(--tw-text-opacity));
}
.hover\:text-primary\/80:hover {
color: hsl(var(--primary) / 0.8);
}
.hover\:text-neutral-500:hover {
--tw-text-opacity: 1;
color: rgb(115 115 115 / var(--tw-text-opacity));
}
.hover\:text-primary\/80:hover {
color: hsl(var(--primary) / 0.8);
}
.hover\:underline:hover {
text-decoration-line: underline;
}
@ -1748,11 +1738,6 @@ body {
--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity));
}
.focus\:ring-blue-500:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity));
}
.focus\:ring-ring:focus {
--tw-ring-opacity: 1;
--tw-ring-color: hsl(var(--ring) / var(--tw-ring-opacity));
@ -1816,6 +1801,16 @@ body {
opacity: 0.7;
}
.dark\:border-destructive:is(.dark *) {
--tw-border-opacity: 1;
border-color: hsl(var(--destructive) / var(--tw-border-opacity));
}
.dark\:border-border:is(.dark *) {
--tw-border-opacity: 1;
border-color: hsl(var(--border) / var(--tw-border-opacity));
}
.dark\:from-gray-900:is(.dark *) {
--tw-gradient-from: #111827 var(--tw-gradient-from-position);
--tw-gradient-to: rgb(17 24 39 / 0) var(--tw-gradient-to-position);
@ -1846,6 +1841,11 @@ body {
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.dark\:text-destructive-foreground:is(.dark *) {
--tw-text-opacity: 1;
color: hsl(var(--destructive-foreground) / var(--tw-text-opacity));
}
.dark\:file\:text-foreground:is(.dark *)::file-selector-button {
--tw-text-opacity: 1;
color: hsl(var(--foreground) / var(--tw-text-opacity));
@ -1953,8 +1953,38 @@ body {
}
}
.\[\&\:has\(svg\)\]\:pl-11:has(svg) {
padding-left: 2.75rem;
}
.\[\&\>svg\+div\]\:translate-y-\[-3px\]>svg+div {
--tw-translate-y: -3px;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.\[\&\>svg\]\:absolute>svg {
position: absolute;
}
.\[\&\>svg\]\:left-4>svg {
left: 1rem;
}
.\[\&\>svg\]\:top-4>svg {
top: 1rem;
}
.\[\&\>svg\]\:text-destructive>svg {
--tw-text-opacity: 1;
color: hsl(var(--destructive) / var(--tw-text-opacity));
}
.\[\&\[aria-expanded\=true\]\>svg\]\:rotate-180[aria-expanded=true]>svg {
--tw-rotate: 180deg;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.\[\&_p\]\:leading-relaxed p {
line-height: 1.625;
}

View File

@ -28,6 +28,7 @@ func main() {
mux.Handle("GET /docs/components/input", templ.Handler(pages.Input()))
mux.Handle("GET /docs/components/accordion", templ.Handler(pages.Accordion()))
mux.Handle("GET /docs/components/datepicker", templ.Handler(pages.Datepicker()))
mux.Handle("GET /docs/components/alert", templ.Handler(pages.Alert()))
fmt.Println("Server is running on http://localhost:8090")
http.ListenAndServe(":8090", mux)

View File

@ -33,6 +33,10 @@ var Sections = []Section{
Text: "Accordion",
Href: "/docs/components/accordion",
},
{
Text: "Alert",
Href: "/docs/components/alert",
},
{
Text: "Button",
Href: "/docs/components/button",

View File

@ -0,0 +1,70 @@
package components
// AlertVariant represents the visual style of the alert.
type AlertVariant string
// Constants for alert variants.
const (
DefaultAlert AlertVariant = "default"
DestructiveAlert AlertVariant = "destructive"
)
// AlertProps defines the properties for the Alert component.
type AlertProps struct {
// Variant determines the visual style of the alert.
// Default: DefaultAlert
Variant AlertVariant
// Class specifies additional CSS classes to apply to the alert.
// Default: "" (empty string)
Class string
}
// getAlertVariantClasses returns the CSS classes for the given alert variant.
func getAlertVariantClasses(variant AlertVariant) string {
switch variant {
case DestructiveAlert:
return "border-destructive text-destructive"
default:
return "border-border text-foreground"
}
}
// Alert renders an alert component based on the provided props and children.
// It can be customized with two visual styles: Default and Destructive.
// All content, including icons, should be passed in as children.
//
// Usage:
//
// @components.Alert(components.AlertProps{Variant: components.DestructiveAlert}) {
// @components.ExclamationTriangleIcon()
// @components.AlertTitle{"Error"}
// @components.AlertDescription{"Your session has expired. Please log in again."}
// }
//
// Props:
// - Variant: The visual style of the alert (DefaultAlert or DestructiveAlert). Default: DefaultAlert
// - Class: Additional CSS classes to apply to the alert. Default: "" (empty string)
templ Alert(props AlertProps) {
<div
class={ "relative w-full rounded-lg border p-4 [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11",
getAlertVariantClasses(props.Variant),
props.Class }
role="alert"
>
{ children... }
</div>
}
// AlertTitle renders the title of the alert.
templ AlertTitle() {
<h5 class="mb-1 font-medium leading-none tracking-tight">
{ children... }
</h5>
}
// AlertDescription renders the description of the alert.
templ AlertDescription() {
<div class="text-sm [&_p]:leading-relaxed">
{ children... }
</div>
}

View File

@ -0,0 +1,39 @@
package pages
import (
"github.com/axzilla/goilerplate/internals/ui/components"
"github.com/axzilla/goilerplate/internals/ui/layouts"
"github.com/axzilla/goilerplate/internals/ui/showcase"
)
templ Alert() {
@layouts.DocsLayout() {
<div>
<div class="mb-16">
<h1 class="text-3xl font-bold mb-2">Alert</h1>
<p class="mb-4 text-muted-foreground">Displays a callout for user attention, often used for notifications, warnings, or important messages.</p>
</div>
@components.Tabs(components.TabsProps{
Tabs: []components.Tab{
{
ID: "preview",
Title: "Preview",
Content: showcase.AlertShowcase(),
},
{
ID: "code",
Title: "Code",
Content: CodeSnippetFromEmbedded("alert.templ", "go", showcase.TemplFiles),
},
{
ID: "component",
Title: "Component",
Content: CodeSnippetFromEmbedded("alert.templ", "go", components.TemplFiles),
},
},
TabsContainerClass: "md:w-1/2",
ContentContainerClass: "w-full",
})
</div>
}
}

View File

@ -0,0 +1,48 @@
package showcase
import (
"github.com/axzilla/goilerplate/internals/ui/components"
)
templ RocketIcon() {
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" class="h-4 w-4"><path d="M6.85357 3.85355L7.65355 3.05353C8.2981 2.40901 9.42858 1.96172 10.552 1.80125C11.1056 1.72217 11.6291 1.71725 12.0564 1.78124C12.4987 1.84748 12.7698 1.97696 12.8965 2.10357C13.0231 2.23018 13.1526 2.50125 13.2188 2.94357C13.2828 3.37086 13.2779 3.89439 13.1988 4.44801C13.0383 5.57139 12.591 6.70188 11.9464 7.34645L7.49999 11.7929L6.35354 10.6465C6.15827 10.4512 5.84169 10.4512 5.64643 10.6465C5.45117 10.8417 5.45117 11.1583 5.64643 11.3536L7.14644 12.8536C7.34171 13.0488 7.65829 13.0488 7.85355 12.8536L8.40073 12.3064L9.57124 14.2572C9.65046 14.3893 9.78608 14.4774 9.9389 14.4963C10.0917 14.5151 10.2447 14.4624 10.3535 14.3536L12.3535 12.3536C12.4648 12.2423 12.5172 12.0851 12.495 11.9293L12.0303 8.67679L12.6536 8.05355C13.509 7.19808 14.0117 5.82855 14.1887 4.58943C14.2784 3.9618 14.2891 3.33847 14.2078 2.79546C14.1287 2.26748 13.9519 1.74482 13.6035 1.39645C13.2552 1.04809 12.7325 0.871332 12.2045 0.792264C11.6615 0.710945 11.0382 0.721644 10.4105 0.8113C9.17143 0.988306 7.80189 1.491 6.94644 2.34642L6.32322 2.96968L3.07071 2.50504C2.91492 2.48278 2.75773 2.53517 2.64645 2.64646L0.646451 4.64645C0.537579 4.75533 0.484938 4.90829 0.50375 5.0611C0.522563 5.21391 0.61073 5.34954 0.742757 5.42876L2.69364 6.59928L2.14646 7.14645C2.0527 7.24022 2.00002 7.3674 2.00002 7.50001C2.00002 7.63261 2.0527 7.75979 2.14646 7.85356L3.64647 9.35356C3.84173 9.54883 4.15831 9.54883 4.35357 9.35356C4.54884 9.1583 4.54884 8.84172 4.35357 8.64646L3.20712 7.50001L3.85357 6.85356L6.85357 3.85355ZM10.0993 13.1936L9.12959 11.5775L11.1464 9.56067L11.4697 11.8232L10.0993 13.1936ZM3.42251 5.87041L5.43935 3.85356L3.17678 3.53034L1.80638 4.90074L3.42251 5.87041ZM2.35356 10.3535C2.54882 10.1583 2.54882 9.8417 2.35356 9.64644C2.1583 9.45118 1.84171 9.45118 1.64645 9.64644L0.646451 10.6464C0.451188 10.8417 0.451188 11.1583 0.646451 11.3535C0.841713 11.5488 1.1583 11.5488 1.35356 11.3535L2.35356 10.3535ZM3.85358 11.8536C4.04884 11.6583 4.04885 11.3417 3.85359 11.1465C3.65833 10.9512 3.34175 10.9512 3.14648 11.1465L1.14645 13.1464C0.95119 13.3417 0.951187 13.6583 1.14645 13.8535C1.34171 14.0488 1.65829 14.0488 1.85355 13.8536L3.85358 11.8536ZM5.35356 13.3535C5.54882 13.1583 5.54882 12.8417 5.35356 12.6464C5.1583 12.4512 4.84171 12.4512 4.64645 12.6464L3.64645 13.6464C3.45119 13.8417 3.45119 14.1583 3.64645 14.3535C3.84171 14.5488 4.1583 14.5488 4.35356 14.3535L5.35356 13.3535ZM9.49997 6.74881C10.1897 6.74881 10.7488 6.1897 10.7488 5.5C10.7488 4.8103 10.1897 4.25118 9.49997 4.25118C8.81026 4.25118 8.25115 4.8103 8.25115 5.5C8.25115 6.1897 8.81026 6.74881 9.49997 6.74881Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg>
}
templ WarningIcon() {
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" class="h-4 w-4"><path d="M8.4449 0.608765C8.0183 -0.107015 6.9817 -0.107015 6.55509 0.608766L0.161178 11.3368C-0.275824 12.07 0.252503 13 1.10608 13H13.8939C14.7475 13 15.2758 12.07 14.8388 11.3368L8.4449 0.608765ZM7.4141 1.12073C7.45288 1.05566 7.54712 1.05566 7.5859 1.12073L13.9798 11.8488C14.0196 11.9154 13.9715 12 13.8939 12H1.10608C1.02849 12 0.980454 11.9154 1.02018 11.8488L7.4141 1.12073ZM6.8269 4.48611C6.81221 4.10423 7.11783 3.78663 7.5 3.78663C7.88217 3.78663 8.18778 4.10423 8.1731 4.48612L8.01921 8.48701C8.00848 8.766 7.7792 8.98664 7.5 8.98664C7.2208 8.98664 6.99151 8.766 6.98078 8.48701L6.8269 4.48611ZM8.24989 10.476C8.24989 10.8902 7.9141 11.226 7.49989 11.226C7.08567 11.226 6.74989 10.8902 6.74989 10.476C6.74989 10.0618 7.08567 9.72599 7.49989 9.72599C7.9141 9.72599 8.24989 10.0618 8.24989 10.476Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg>
}
templ AlertShowcase() {
<div class="flex justify-center items-center border rounded-md py-16 px-4">
<div class="space-y-4 max-w-md w-full">
<div class="mb-8">
<h2 class="font-semibold mb-2">Default Alert</h2>
<div class="space-y-2">
@components.Alert(components.AlertProps{Variant: components.DefaultAlert}) {
@RocketIcon()
@components.AlertTitle() {
Note
}
@components.AlertDescription() {
This is a default alert — check it out!
}
}
</div>
</div>
<div class="mb-8">
<h2 class="font-semibold mb-2">Destructive Alert</h2>
<div class="space-y-2">
@components.Alert(components.AlertProps{Variant: components.DestructiveAlert}) {
@WarningIcon()
@components.AlertTitle() {
Error
}
@components.AlertDescription() {
Your session has expired. Please log in again.
}
}
</div>
</div>
</div>
</div>
}