384 lines
7.6 KiB
Text
384 lines
7.6 KiB
Text
// templui component dropdown - version: v0.84.0 installed by templui v0.84.0
|
|
package dropdown
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"git.jmbit.de/jmb/scanfile/server/web/templui/components/popover"
|
|
"git.jmbit.de/jmb/scanfile/server/web/templui/utils"
|
|
)
|
|
|
|
type contextKey string
|
|
|
|
var (
|
|
contentIDKey contextKey = "contentID"
|
|
subContentIDKey contextKey = "subContentID"
|
|
)
|
|
|
|
type Props struct {
|
|
ID string
|
|
Class string
|
|
Attributes templ.Attributes
|
|
}
|
|
|
|
type TriggerProps struct {
|
|
ID string
|
|
Class string
|
|
Attributes templ.Attributes
|
|
}
|
|
|
|
type ContentProps struct {
|
|
ID string
|
|
Class string
|
|
Attributes templ.Attributes
|
|
Width string
|
|
MaxHeight string
|
|
Align string
|
|
Side string
|
|
}
|
|
|
|
type GroupProps struct {
|
|
ID string
|
|
Class string
|
|
Attributes templ.Attributes
|
|
}
|
|
|
|
type LabelProps struct {
|
|
ID string
|
|
Class string
|
|
Attributes templ.Attributes
|
|
}
|
|
|
|
type ItemProps struct {
|
|
ID string
|
|
Class string
|
|
Attributes templ.Attributes
|
|
Disabled bool
|
|
Href string
|
|
Target string
|
|
PreventClose bool
|
|
}
|
|
|
|
type SeparatorProps struct {
|
|
ID string
|
|
Class string
|
|
Attributes templ.Attributes
|
|
}
|
|
|
|
type ShortcutProps struct {
|
|
ID string
|
|
Class string
|
|
Attributes templ.Attributes
|
|
}
|
|
|
|
type SubProps struct {
|
|
ID string
|
|
Class string
|
|
Attributes templ.Attributes
|
|
}
|
|
|
|
type SubTriggerProps struct {
|
|
ID string
|
|
Class string
|
|
Attributes templ.Attributes
|
|
}
|
|
|
|
type SubContentProps struct {
|
|
ID string
|
|
Class string
|
|
Attributes templ.Attributes
|
|
}
|
|
|
|
type PortalProps struct {
|
|
ID string
|
|
Class string
|
|
Attributes templ.Attributes
|
|
}
|
|
|
|
templ Dropdown(props ...Props) {
|
|
{{
|
|
var p Props
|
|
if len(props) > 0 {
|
|
p = props[0]
|
|
}
|
|
contentID := p.ID
|
|
if contentID == "" {
|
|
contentID = utils.RandomID()
|
|
}
|
|
ctx = context.WithValue(ctx, contentIDKey, contentID)
|
|
}}
|
|
{ children... }
|
|
}
|
|
|
|
templ Trigger(props ...TriggerProps) {
|
|
{{
|
|
var p TriggerProps
|
|
if len(props) > 0 {
|
|
p = props[0]
|
|
}
|
|
contentID, ok := ctx.Value(contentIDKey).(string)
|
|
if !ok {
|
|
contentID = "fallback-content-id"
|
|
}
|
|
}}
|
|
@popover.Trigger(popover.TriggerProps{
|
|
ID: p.ID,
|
|
For: contentID, TriggerType: popover.TriggerTypeClick,
|
|
}) {
|
|
<span
|
|
class={ utils.TwMerge("inline-block", p.Class) }
|
|
{ p.Attributes... }
|
|
>
|
|
{ children... }
|
|
</span>
|
|
}
|
|
}
|
|
|
|
templ Content(props ...ContentProps) {
|
|
{{ var p ContentProps }}
|
|
if len(props) > 0 {
|
|
{{ p = props[0] }}
|
|
}
|
|
{{ contentID, ok := ctx.Value(contentIDKey).(string) }}
|
|
if !ok {
|
|
{{ contentID = "fallback-content-id" }} // Must match fallback in Trigger
|
|
}
|
|
{{
|
|
var maxHeight string = "300px"
|
|
if p.MaxHeight != "" {
|
|
maxHeight = p.MaxHeight
|
|
}
|
|
maxHeightClass := fmt.Sprintf("max-h-[%s]", maxHeight)
|
|
}}
|
|
@popover.Content(popover.ContentProps{
|
|
ID: contentID,
|
|
Placement: popover.PlacementBottomStart,
|
|
Offset: 4,
|
|
Class: utils.TwMerge(
|
|
"z-50 rounded-md bg-popover p-1 shadow-md focus:outline-none overflow-auto",
|
|
"border border-border",
|
|
"min-w-[8rem]",
|
|
maxHeightClass,
|
|
p.Width,
|
|
p.Class,
|
|
),
|
|
Attributes: p.Attributes,
|
|
}) {
|
|
{ children... }
|
|
}
|
|
}
|
|
|
|
templ Group(props ...GroupProps) {
|
|
{{ var p GroupProps }}
|
|
if len(props) > 0 {
|
|
{{ p = props[0] }}
|
|
}
|
|
<div
|
|
if p.ID != "" {
|
|
id={ p.ID }
|
|
}
|
|
class={ utils.TwMerge("py-1", p.Class) }
|
|
role="group"
|
|
{ p.Attributes... }
|
|
>
|
|
{ children... }
|
|
</div>
|
|
}
|
|
|
|
templ Label(props ...LabelProps) {
|
|
{{ var p LabelProps }}
|
|
if len(props) > 0 {
|
|
{{ p = props[0] }}
|
|
}
|
|
<div
|
|
if p.ID != "" {
|
|
id={ p.ID }
|
|
}
|
|
class={ utils.TwMerge("px-2 py-1.5 text-sm font-semibold", p.Class) }
|
|
{ p.Attributes... }
|
|
>
|
|
{ children... }
|
|
</div>
|
|
}
|
|
|
|
templ Item(props ...ItemProps) {
|
|
{{ var p ItemProps }}
|
|
if len(props) > 0 {
|
|
{{ p = props[0] }}
|
|
}
|
|
if p.ID == "" {
|
|
{{ p.ID = utils.RandomID() }}
|
|
}
|
|
if p.Href != "" {
|
|
<a
|
|
id={ p.ID }
|
|
if p.Href != "" {
|
|
href={ templ.SafeURL(p.Href) }
|
|
}
|
|
if p.Target != "" {
|
|
target={ p.Target }
|
|
}
|
|
class={
|
|
utils.TwMerge(
|
|
"flex text-left items-center px-2 py-1.5 text-sm rounded-sm",
|
|
utils.If(!p.Disabled, "focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground cursor-default"),
|
|
utils.If(p.Disabled, "opacity-50 pointer-events-none"),
|
|
p.Class,
|
|
),
|
|
}
|
|
role="menuitem"
|
|
data-dropdown-item
|
|
if p.PreventClose {
|
|
data-prevent-close="true"
|
|
}
|
|
{ p.Attributes... }
|
|
>
|
|
{ children... }
|
|
</a>
|
|
} else {
|
|
<button
|
|
id={ p.ID }
|
|
class={
|
|
utils.TwMerge(
|
|
"w-full text-left flex items-center justify-between px-2 py-1.5 text-sm rounded-sm",
|
|
utils.If(!p.Disabled, "focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground cursor-default"),
|
|
utils.If(p.Disabled, "opacity-50 pointer-events-none"),
|
|
p.Class,
|
|
),
|
|
}
|
|
role="menuitem"
|
|
data-dropdown-item
|
|
disabled?={ p.Disabled }
|
|
if p.PreventClose {
|
|
data-prevent-close="true"
|
|
}
|
|
{ p.Attributes... }
|
|
>
|
|
{ children... }
|
|
</button>
|
|
}
|
|
}
|
|
|
|
templ Separator(props ...SeparatorProps) {
|
|
{{ var p SeparatorProps }}
|
|
if len(props) > 0 {
|
|
{{ p = props[0] }}
|
|
}
|
|
<div
|
|
if p.ID != "" {
|
|
id={ p.ID }
|
|
}
|
|
class={ utils.TwMerge("h-px my-1 -mx-1 bg-muted", p.Class) }
|
|
role="separator"
|
|
{ p.Attributes... }
|
|
></div>
|
|
}
|
|
|
|
templ Shortcut(props ...ShortcutProps) {
|
|
{{ var p ShortcutProps }}
|
|
if len(props) > 0 {
|
|
{{ p = props[0] }}
|
|
}
|
|
<span
|
|
if p.ID != "" {
|
|
id={ p.ID }
|
|
}
|
|
class={ utils.TwMerge("ml-auto text-xs tracking-widest opacity-60", p.Class) }
|
|
{ p.Attributes... }
|
|
>
|
|
{ children... }
|
|
</span>
|
|
}
|
|
|
|
templ Sub(props ...SubProps) {
|
|
{{
|
|
var p SubProps
|
|
if len(props) > 0 {
|
|
p = props[0]
|
|
}
|
|
subContentID := p.ID
|
|
if subContentID == "" {
|
|
subContentID = utils.RandomID()
|
|
}
|
|
ctx = context.WithValue(ctx, subContentIDKey, subContentID)
|
|
}}
|
|
<div
|
|
if p.ID != "" {
|
|
id={ p.ID }
|
|
}
|
|
data-dropdown-submenu
|
|
class={ utils.TwMerge("relative", p.Class) }
|
|
{ p.Attributes... }
|
|
>
|
|
{ children... }
|
|
</div>
|
|
}
|
|
|
|
templ SubTrigger(props ...SubTriggerProps) {
|
|
{{
|
|
var p SubTriggerProps
|
|
if len(props) > 0 {
|
|
p = props[0]
|
|
}
|
|
subContentID, ok := ctx.Value(subContentIDKey).(string)
|
|
if !ok {
|
|
subContentID = "fallback-subcontent-id"
|
|
}
|
|
}}
|
|
@popover.Trigger(popover.TriggerProps{
|
|
ID: p.ID,
|
|
For: subContentID,
|
|
TriggerType: popover.TriggerTypeHover,
|
|
}) {
|
|
<button
|
|
type="button"
|
|
data-dropdown-submenu-trigger
|
|
class={
|
|
utils.TwMerge(
|
|
"w-full text-left flex items-center justify-between px-2 py-1.5 text-sm rounded-sm",
|
|
"focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground cursor-default",
|
|
p.Class,
|
|
),
|
|
}
|
|
{ p.Attributes... }
|
|
>
|
|
<span>
|
|
{ children... }
|
|
</span>
|
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-auto">
|
|
<path d="M6.5 3L11.5 8L6.5 13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
</svg>
|
|
</button>
|
|
}
|
|
}
|
|
|
|
templ SubContent(props ...SubContentProps) {
|
|
{{
|
|
var p SubContentProps
|
|
if len(props) > 0 {
|
|
p = props[0]
|
|
}
|
|
subContentID, ok := ctx.Value(subContentIDKey).(string)
|
|
if !ok {
|
|
subContentID = "fallback-subcontent-id"
|
|
}
|
|
}}
|
|
@popover.Content(popover.ContentProps{
|
|
ID: subContentID,
|
|
Placement: popover.PlacementRightStart,
|
|
Offset: -4, // Adjust as needed
|
|
HoverDelay: 100, // ms
|
|
HoverOutDelay: 200, // ms
|
|
Class: utils.TwMerge(
|
|
"z-[9999] min-w-[8rem] rounded-md border bg-popover p-1 shadow-lg",
|
|
p.Class,
|
|
),
|
|
Attributes: p.Attributes,
|
|
}) {
|
|
{ children... }
|
|
}
|
|
}
|
|
|
|
templ Script() {
|
|
<script defer src="/assets/js/dropdown.min.js"></script>
|
|
}
|