1
0
mirror of https://github.com/axzilla/templui.git synced 2025-02-21 22:12:41 +00:00

feat: add avatar component

This commit is contained in:
“axzilla” 2024-10-08 12:38:11 +02:00
parent 4b175edac6
commit 1df0a9bc58
7 changed files with 244 additions and 6 deletions

View File

@ -2,6 +2,10 @@
## 2024-10-07
- Added: Avatar component
## 2024-10-07
- Added: Input component
- Added: Modal component
- Added: Alert component

View File

@ -871,6 +871,14 @@ body {
height: 1.25rem;
}
.h-12 {
height: 3rem;
}
.h-16 {
height: 4rem;
}
.\!max-h-\[501px\] {
max-height: 501px !important;
}
@ -931,6 +939,18 @@ body {
width: 1.25rem;
}
.w-12 {
width: 3rem;
}
.w-16 {
width: 4rem;
}
.w-8 {
width: 2rem;
}
.max-w-3xl {
max-width: 48rem;
}
@ -1166,6 +1186,10 @@ body {
border-width: 1px;
}
.border-2 {
border-width: 2px;
}
.border-b {
border-bottom-width: 1px;
}
@ -1210,6 +1234,11 @@ body {
border-color: transparent;
}
.border-blue-500 {
--tw-border-opacity: 1;
border-color: rgb(59 130 246 / var(--tw-border-opacity));
}
.bg-background {
--tw-bg-opacity: 1;
background-color: hsl(var(--background) / var(--tw-bg-opacity));
@ -1308,6 +1337,11 @@ body {
object-fit: contain;
}
.object-cover {
-o-object-fit: cover;
object-fit: cover;
}
.p-1 {
padding: 0.25rem;
}

View File

@ -21,15 +21,17 @@ func main() {
mux.Handle("GET /docs/getting-started", http.RedirectHandler("/docs/introduction", http.StatusSeeOther))
mux.Handle("GET /docs/introduction", templ.Handler(pages.Introduction()))
mux.Handle("GET /docs/how-to-use", templ.Handler(pages.HowToUse()))
// Components
mux.Handle("GET /docs/components/accordion", templ.Handler(pages.Accordion()))
mux.Handle("GET /docs/components/alert", templ.Handler(pages.Alert()))
mux.Handle("GET /docs/components/avatar", templ.Handler(pages.Avatar()))
mux.Handle("GET /docs/components/button", templ.Handler(pages.Button()))
mux.Handle("GET /docs/components/card", templ.Handler(pages.Card()))
mux.Handle("GET /docs/components/datepicker", templ.Handler(pages.Datepicker()))
mux.Handle("GET /docs/components/input", templ.Handler(pages.Input()))
mux.Handle("GET /docs/components/modal", templ.Handler(pages.Modal()))
mux.Handle("GET /docs/components/sheet", templ.Handler(pages.Sheet()))
mux.Handle("GET /docs/components/tabs", templ.Handler(pages.Tabs()))
mux.Handle("GET /docs/components/card", templ.Handler(pages.Card()))
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()))
mux.Handle("GET /docs/components/modal", templ.Handler(pages.Modal()))
fmt.Println("Server is running on http://localhost:8090")
http.ListenAndServe(":8090", mux)

View File

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

View File

@ -0,0 +1,103 @@
package components
import (
"fmt"
"strings"
)
// AvatarSize represents the size of the avatar.
type AvatarSize string
const (
AvatarSizeSmall AvatarSize = "small"
AvatarSizeMedium AvatarSize = "medium"
AvatarSizeLarge AvatarSize = "large"
)
// AvatarProps defines the properties for the Avatar component.
type AvatarProps struct {
// ImageSrc is the URL of the avatar image.
// If empty, initials will be used.
ImageSrc string
// Name is used to generate initials if ImageSrc is empty.
Name string
// Size determines the size of the avatar.
// Default: AvatarSizeMedium
Size AvatarSize
// Class specifies additional CSS classes to apply to the avatar.
Class string
// Attributes allows passing additional HTML attributes to the avatar element.
Attributes templ.Attributes
}
// getInitials generates initials from the given name.
func AvatarInitials(name string) string {
parts := strings.Fields(name)
initials := ""
for i, part := range parts {
if i > 1 {
break
}
if len(part) > 0 {
initials += string(part[0])
}
}
return strings.ToUpper(initials)
}
// getSizeClasses returns the CSS classes for the given avatar size.
func AvatarSizeClasses(size AvatarSize) string {
switch size {
case AvatarSizeSmall:
return "w-8 h-8 text-xs"
case AvatarSizeLarge:
return "w-16 h-16 text-xl"
default:
return "w-12 h-12 text-base"
}
}
// Avatar renders an avatar component based on the provided props.
// It displays an image if ImageSrc is provided, otherwise it shows initials.
//
// Usage:
//
// @components.Avatar(components.AvatarProps{
// ImageSrc: "https://example.com/avatar.jpg",
// Name: "John Doe",
// Size: components.AvatarSizeMedium,
// Class: "border-2 border-blue-500",
// })
//
// Props:
// - ImageSrc: The URL of the avatar image. Default: "" (empty string)
// - Name: The name used to generate initials if ImageSrc is empty. Default: "" (empty string)
// - Size: The size of the avatar (AvatarSizeSmall, AvatarSizeMedium, AvatarSizeLarge). Default: AvatarSizeMedium
// - Class: Additional CSS classes to apply to the avatar. Default: "" (empty string)
// - Attributes: Additional HTML attributes to apply to the avatar element. Default: nil
templ Avatar(props AvatarProps) {
<div
class={
"inline-flex items-center justify-center rounded-full bg-muted",
AvatarSizeClasses(props.Size),
props.Class,
}
{ props.Attributes... }
>
if props.ImageSrc != "" {
<img
src={ props.ImageSrc }
alt={ fmt.Sprintf("%s's avatar", props.Name) }
class="w-full h-full object-cover rounded-full"
/>
} else {
<span class="font-medium text-muted-foreground">
{ AvatarInitials(props.Name) }
</span>
}
</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 Avatar() {
@layouts.DocsLayout() {
<div>
<div class="mb-16">
<h1 class="text-3xl font-bold mb-2">Avatar</h1>
<p class="mb-4 text-muted-foreground">An image element with a fallback for representing the user.</p>
</div>
@components.Tabs(components.TabsProps{
Tabs: []components.Tab{
{
ID: "preview",
Title: "Preview",
Content: showcase.AvatarShowcase(),
},
{
ID: "code",
Title: "Code",
Content: CodeSnippetFromEmbedded("avatar.templ", "go", showcase.TemplFiles),
},
{
ID: "component",
Title: "Component",
Content: CodeSnippetFromEmbedded("avatar.templ", "go", components.TemplFiles),
},
},
TabsContainerClass: "md:w-1/2",
ContentContainerClass: "w-full",
})
</div>
}
}

View File

@ -0,0 +1,52 @@
package showcase
import (
"github.com/axzilla/goilerplate/internals/ui/components"
)
templ AvatarShowcase() {
<div class="flex justify-center items-center border rounded-md py-16 px-4">
<div>
<div class="mb-8">
<h2 class="font-semibold mb-2">With Image</h2>
<div class="flex flex-wrap gap-2">
@components.Avatar(components.AvatarProps{
ImageSrc: "https://avatars.githubusercontent.com/u/26936893?v=4",
Name: "John Doe",
Class: "border-2 border-border",
})
</div>
</div>
<div class="mb-8">
<h2 class="font-semibold mb-2">With Placeholder</h2>
<div class="flex flex-wrap gap-2">
@components.Avatar(components.AvatarProps{
Name: "The Dude",
})
</div>
</div>
<div class="mb-8">
<h2 class="font-semibold mb-2">With Sizes</h2>
<div class="flex flex-wrap gap-2">
@components.Avatar(components.AvatarProps{
ImageSrc: "https://avatars.githubusercontent.com/u/26936893?v=4",
Name: "John Doe",
Size: components.AvatarSizeSmall,
Class: "border-2 border-border",
})
@components.Avatar(components.AvatarProps{
ImageSrc: "https://avatars.githubusercontent.com/u/26936893?v=4",
Name: "John Doe",
Class: "border-2 border-border",
})
@components.Avatar(components.AvatarProps{
ImageSrc: "https://avatars.githubusercontent.com/u/26936893?v=4",
Name: "John Doe",
Size: components.AvatarSizeLarge,
Class: "border-2 border-border",
})
</div>
</div>
</div>
</div>
}