scanfile/server/web/templui/components/rating/rating.templ

188 lines
3.3 KiB
Text

// templui component rating - version: v0.84.0 installed by templui v0.84.0
package rating
import (
"fmt"
"git.jmbit.de/jmb/scanfile/server/web/templui/components/icon"
"git.jmbit.de/jmb/scanfile/server/web/templui/utils"
"strconv"
)
type Style string
const (
StyleStar Style = "star"
StyleHeart Style = "heart"
StyleEmoji Style = "emoji"
)
type Props struct {
ID string
Class string
Attributes templ.Attributes
Value float64
ReadOnly bool
Precision float64
Name string
OnlyInteger bool
}
type GroupProps struct {
ID string
Class string
Attributes templ.Attributes
}
type ItemProps struct {
ID string
Class string
Attributes templ.Attributes
Value int
Style Style
}
templ Rating(props ...Props) {
{{ var p Props }}
if len(props) > 0 {
{{ p = props[0] }}
}
{{ p.setDefaults() }}
<div
if p.ID != "" {
id={ p.ID }
}
data-rating-component
data-initial-value={ fmt.Sprintf("%.2f", p.Value) }
data-precision={ fmt.Sprintf("%.2f", p.Precision) }
data-readonly={ strconv.FormatBool(p.ReadOnly) }
if p.Name != "" {
data-name={ p.Name }
}
data-onlyinteger={ strconv.FormatBool(p.OnlyInteger) }
class={
utils.TwMerge(
"flex flex-col items-start gap-1",
p.Class,
),
}
{ p.Attributes... }
>
{ children... }
if p.Name != "" {
<input
type="hidden"
name={ p.Name }
value={ fmt.Sprintf("%.2f", p.Value) }
data-rating-input
/>
}
</div>
}
templ Group(props ...GroupProps) {
{{ var p GroupProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={ utils.TwMerge("flex flex-row items-center gap-1", p.Class) }
{ p.Attributes... }
>
{ children... }
</div>
}
templ Item(props ...ItemProps) {
{{ var p ItemProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
{{ p.setDefaults() }}
<div
if p.ID != "" {
id={ p.ID }
}
data-rating-item
data-rating-value={ strconv.Itoa(p.Value) }
class={
utils.TwMerge(
"relative",
colorClass(p.Style),
"transition-opacity",
"cursor-pointer", // Default cursor
p.Class,
),
}
{ p.Attributes... }
>
<div class="opacity-30">
@ratingIcon(p.Style, false, float64(p.Value))
</div>
<div
class="absolute inset-0 overflow-hidden w-0"
data-rating-item-foreground
>
@ratingIcon(p.Style, true, float64(p.Value))
</div>
</div>
}
func colorClass(style Style) string {
switch style {
case StyleHeart:
return "text-destructive"
case StyleEmoji:
return "text-yellow-500"
default:
return "text-yellow-400"
}
}
func ratingIcon(style Style, filled bool, value float64) templ.Component {
if style == StyleEmoji {
if filled {
switch {
case value <= 1:
return icon.Angry()
case value <= 2:
return icon.Frown()
case value <= 3:
return icon.Meh()
case value <= 4:
return icon.Smile()
default:
return icon.Laugh()
}
}
return icon.Meh()
}
iconProps := icon.Props{}
if filled {
iconProps.Fill = "currentColor"
}
switch style {
case StyleHeart:
return icon.Heart(iconProps)
default:
return icon.Star(iconProps)
}
}
func (p *ItemProps) setDefaults() {
if p.Style == "" {
p.Style = StyleStar
}
}
func (p *Props) setDefaults() {
if p.Precision <= 0 {
p.Precision = 1.0
}
}
templ Script() {
<script defer src="/assets/js/rating.min.js"></script>
}