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

feat: add dropdown menu component

This commit is contained in:
“axzilla” 2024-10-10 15:14:43 +02:00
parent b4de2f5cb7
commit 6684f6bb45
8 changed files with 612 additions and 0 deletions

View File

@ -666,6 +666,10 @@ body {
bottom: 1rem;
}
.bottom-full {
bottom: 100%;
}
.left-0 {
left: 0px;
}
@ -690,6 +694,10 @@ body {
top: 0.5rem;
}
.top-full {
top: 100%;
}
.z-10 {
z-index: 10;
}
@ -711,6 +719,10 @@ body {
margin-right: auto;
}
.-mr-1 {
margin-right: -0.25rem;
}
.mb-1 {
margin-bottom: 0.25rem;
}
@ -747,6 +759,10 @@ body {
margin-left: 0.25rem;
}
.ml-2 {
margin-left: 0.5rem;
}
.mr-2 {
margin-right: 0.5rem;
}
@ -887,6 +903,10 @@ body {
width: 1.25rem;
}
.w-56 {
width: 14rem;
}
.w-6 {
width: 1.5rem;
}
@ -991,6 +1011,18 @@ body {
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));
}
.scale-100 {
--tw-scale-x: 1;
--tw-scale-y: 1;
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));
}
.scale-95 {
--tw-scale-x: .95;
--tw-scale-y: .95;
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));
}
.transform {
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));
}
@ -1199,6 +1231,11 @@ body {
border-color: hsl(var(--foreground) / var(--tw-border-opacity));
}
.border-gray-300 {
--tw-border-opacity: 1;
border-color: rgb(209 213 219 / var(--tw-border-opacity));
}
.border-input {
--tw-border-opacity: 1;
border-color: hsl(var(--input) / var(--tw-border-opacity));
@ -1631,6 +1668,21 @@ body {
outline-style: solid;
}
.ring-1 {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
}
.ring-black {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity));
}
.ring-opacity-5 {
--tw-ring-opacity: 0.05;
}
.ring-offset-background {
--tw-ring-offset-color: hsl(var(--background) / 1);
}
@ -1687,6 +1739,10 @@ body {
transition-duration: 300ms;
}
.duration-75 {
transition-duration: 75ms;
}
.ease-in {
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
}
@ -1749,6 +1805,11 @@ body {
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
}
.hover\:bg-gray-50:hover {
--tw-bg-opacity: 1;
background-color: rgb(249 250 251 / var(--tw-bg-opacity));
}
.hover\:bg-gray-600:hover {
--tw-bg-opacity: 1;
background-color: rgb(75 85 99 / var(--tw-bg-opacity));
@ -1787,6 +1848,11 @@ body {
color: rgb(107 114 128 / var(--tw-text-opacity));
}
.hover\:text-gray-900:hover {
--tw-text-opacity: 1;
color: rgb(17 24 39 / var(--tw-text-opacity));
}
.hover\:text-green-700:hover {
--tw-text-opacity: 1;
color: rgb(21 128 61 / var(--tw-text-opacity));
@ -1824,6 +1890,10 @@ body {
--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity));
}
.focus\:ring-offset-2:focus {
--tw-ring-offset-width: 2px;
}
.focus-visible\:outline-none:focus-visible {
outline: 2px solid transparent;
outline-offset: 2px;
@ -1878,6 +1948,16 @@ body {
opacity: 0.7;
}
.dark\:border-gray-600:is(.dark *) {
--tw-border-opacity: 1;
border-color: rgb(75 85 99 / var(--tw-border-opacity));
}
.dark\:bg-gray-800:is(.dark *) {
--tw-bg-opacity: 1;
background-color: rgb(31 41 55 / var(--tw-bg-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);
@ -1908,6 +1988,11 @@ body {
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.dark\:ring-gray-700:is(.dark *) {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(55 65 81 / var(--tw-ring-opacity));
}
.dark\:file\:text-foreground:is(.dark *)::file-selector-button {
--tw-text-opacity: 1;
color: hsl(var(--foreground) / var(--tw-text-opacity));
@ -1918,6 +2003,16 @@ body {
background-color: rgb(55 65 81 / var(--tw-bg-opacity));
}
.dark\:hover\:text-white:hover:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.dark\:focus\:ring-indigo-400:focus:is(.dark *) {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(129 140 248 / var(--tw-ring-opacity));
}
@media (min-width: 640px) {
.sm\:my-8 {
margin-top: 2rem;

View File

@ -28,6 +28,7 @@ func main() {
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/dropdown-menu", templ.Handler(pages.DropdownMenu()))
mux.Handle("GET /docs/components/icon", templ.Handler(pages.Icon()))
mux.Handle("GET /docs/components/input", templ.Handler(pages.Input()))
mux.Handle("GET /docs/components/modal", templ.Handler(pages.Modal()))

View File

@ -53,6 +53,10 @@ var Sections = []Section{
Text: "Datepicker",
Href: "/docs/components/datepicker",
},
{
Text: "Dropdown Menu",
Href: "/docs/components/dropdown-menu",
},
{
Text: "Icon",
Href: "/docs/components/icon",

View File

@ -0,0 +1,39 @@
package pages
import (
"github.com/axzilla/goilerplate/pkg/components"
"github.com/axzilla/goilerplate/internals/ui/layouts"
"github.com/axzilla/goilerplate/internals/ui/showcase"
)
templ DropdownMenu() {
@layouts.DocsLayout() {
<div>
<div class="mb-16">
<h1 class="text-3xl font-bold mb-2">Dropdown Menu</h1>
<p class="mb-4 text-muted-foreground">The Dropdown Menu component provides a way to display a list of options in a compact form.</p>
</div>
@components.Tabs(components.TabsProps{
Tabs: []components.Tab{
{
ID: "preview",
Title: "Preview",
Content: showcase.DropdownMenuShowcase(),
},
{
ID: "code",
Title: "Code",
Content: CodeSnippetFromEmbedded("dropdown_menu.templ", "go", showcase.TemplFiles),
},
{
ID: "component",
Title: "Component",
Content: CodeSnippetFromEmbedded("dropdown_menu.templ", "go", components.TemplFiles),
},
},
TabsContainerClass: "md:w-1/2",
ContentContainerClass: "w-full",
})
</div>
}
}

View File

@ -0,0 +1,20 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ DropdownMenuShowcase() {
<div class="flex justify-center items-center border rounded-md py-16 px-4">
<div class="flex gap-2 flex-wrap">
@components.DropdownMenu(components.DropdownMenuProps{
Label: "Click me",
Position: "left",
Items: []components.DropdownMenuItem{
{Label: "Option 1", Value: "option1"},
{Label: "Option 2", Value: "option2"},
{Label: "Option 3", Value: "option3"},
{Label: "With Link", Href: "https://github.com/axzilla/goilerplate", Target: "_blank"},
},
})
</div>
</div>
}

View File

@ -0,0 +1,134 @@
package components
import (
"fmt"
)
// DropdownMenuItem represents an item in the dropdown menu
type DropdownMenuItem struct {
Label string
Value string
Href string
Target string
}
// DropdownMenuProps defines the properties for the DropdownMenu component
type DropdownMenuProps struct {
Items []DropdownMenuItem
Label string
Class string
Position string // "left" or "right", defaults to right if not specified
}
// DropdownMenu renders a dropdown menu component.
//
// It provides a button that, when clicked, displays a list of options.
// The menu can be positioned to the left or right of the button.
// It supports both button and link items, with optional target attribute for links.
//
// Props:
// - Items: Slice of DropdownMenuItem, defining the content of the dropdown
// - Label: Text to display on the dropdown button
// - Class: Additional CSS classes to apply to the root element
// - Position: "left" or "right", determines the horizontal position of the dropdown
//
// DropdownMenuItem fields:
// - Label: Text to display for the item
// - Value: Value associated with the item (for button items)
// - Href: URL for link items
// - Target: Target attribute for link items (e.g., "_blank" for new tab)
//
// Usage:
//
// @components.DropdownMenu(components.DropdownMenuProps{
// Label: "Options",
// Position: "right",
// Items: []components.DropdownMenuItem{
// {Label: "Option 1", Value: "opt1"},
// {Label: "Option 2", Value: "opt2"},
// {Label: "External Link", Href: "https://example.com", Target: "_blank"},
// },
// })
//
// The component uses Alpine.js for interactivity and Tailwind CSS for styling.
// It includes dark mode support and responsive positioning.
templ DropdownMenu(props DropdownMenuProps) {
<div
class={ "relative inline-block text-left", props.Class }
x-data="{
open: false,
position: $el.dataset.position,
verticalPosition: 'bottom',
updatePosition() {
const menu = this.$refs.menu;
const rect = menu.getBoundingClientRect();
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
if (this.position === 'left' && rect.left < 0) {
this.position = 'right';
} else if (this.position !== 'left' && rect.right > viewportWidth) {
this.position = 'left';
}
if (this.verticalPosition === 'bottom' && rect.bottom > viewportHeight) {
this.verticalPosition = 'top';
} else if (this.verticalPosition === 'top' && rect.top < 0) {
this.verticalPosition = 'bottom';
}
}
}"
@resize.window="if (open) updatePosition()"
data-position={ props.Position }
>
<button
type="button"
class="inline-flex justify-center w-full rounded-md border border-gray-300 dark:border-gray-600 shadow-sm px-4 py-2 bg-white dark:bg-gray-800 text-sm font-medium text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-indigo-400"
id="dropdown-menu-button"
@click="open = !open; if (open) $nextTick(() => updatePosition())"
>
{ props.Label }
<svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"></path>
</svg>
</button>
<div
x-ref="menu"
x-show="open"
@click.away="open = false"
x-transition:enter="transition ease-out duration-100"
x-transition:enter-start="transform opacity-0 scale-95"
x-transition:enter-end="transform opacity-100 scale-100"
x-transition:leave="transition ease-in duration-75"
x-transition:leave-start="transform opacity-100 scale-100"
x-transition:leave-end="transform opacity-0 scale-95"
:class="{
'right-0': position === 'left',
'left-0': position !== 'left',
'bottom-full mb-2': verticalPosition === 'top',
'top-full mt-2': verticalPosition === 'bottom'
}"
class="absolute w-56 rounded-md shadow-lg bg-white dark:bg-gray-800 ring-1 ring-black ring-opacity-5 dark:ring-gray-700 focus:outline-none z-10"
>
<div class="py-1" role="menu" aria-orientation="vertical" aria-labelledby="dropdown-menu-button">
for _, item := range props.Items {
if item.Href != "" {
<a
href={ templ.SafeURL(item.Href) }
target={ item.Target }
class="block px-4 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white"
role="menuitem"
>{ item.Label }</a>
} else {
<button
type="button"
class="block w-full text-left px-4 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white"
role="menuitem"
@click={ fmt.Sprintf("$dispatch('dropdown-selected', { value: '%s' }); open = false", item.Value) }
>{ item.Label }</button>
}
}
</div>
</div>
</div>
}

View File

@ -0,0 +1,214 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package components
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import (
"fmt"
)
// DropdownMenuItem represents an item in the dropdown menu
type DropdownMenuItem struct {
Label string
Value string
Href string
Target string
}
// DropdownMenuProps defines the properties for the DropdownMenu component
type DropdownMenuProps struct {
Items []DropdownMenuItem
Label string
Class string
Position string // "left" or "right", defaults to right if not specified
}
// DropdownMenu renders a dropdown menu component.
//
// It provides a button that, when clicked, displays a list of options.
// The menu can be positioned to the left or right of the button.
// It supports both button and link items, with optional target attribute for links.
//
// Props:
// - Items: Slice of DropdownMenuItem, defining the content of the dropdown
// - Label: Text to display on the dropdown button
// - Class: Additional CSS classes to apply to the root element
// - Position: "left" or "right", determines the horizontal position of the dropdown
//
// DropdownMenuItem fields:
// - Label: Text to display for the item
// - Value: Value associated with the item (for button items)
// - Href: URL for link items
// - Target: Target attribute for link items (e.g., "_blank" for new tab)
//
// Usage:
//
// @components.DropdownMenu(components.DropdownMenuProps{
// Label: "Options",
// Position: "right",
// Items: []components.DropdownMenuItem{
// {Label: "Option 1", Value: "opt1"},
// {Label: "Option 2", Value: "opt2"},
// {Label: "External Link", Href: "https://example.com", Target: "_blank"},
// },
// })
//
// The component uses Alpine.js for interactivity and Tailwind CSS for styling.
// It includes dark mode support and responsive positioning.
func DropdownMenu(props DropdownMenuProps) templ.Component {
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
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var2 = []any{"relative inline-block text-left", props.Class}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" x-data=\"{ \n\t\t\topen: false,\n\t\t\tposition: $el.dataset.position,\n\t\t\tverticalPosition: &#39;bottom&#39;,\n\t\t\tupdatePosition() {\n\t\t\t\tconst menu = this.$refs.menu;\n\t\t\t\tconst rect = menu.getBoundingClientRect();\n\t\t\t\tconst viewportWidth = window.innerWidth || document.documentElement.clientWidth;\n\t\t\t\tconst viewportHeight = window.innerHeight || document.documentElement.clientHeight;\n\t\t\t\t\n\t\t\t\tif (this.position === &#39;left&#39; &amp;&amp; rect.left &lt; 0) {\n\t\t\t\t\tthis.position = &#39;right&#39;;\n\t\t\t\t} else if (this.position !== &#39;left&#39; &amp;&amp; rect.right &gt; viewportWidth) {\n\t\t\t\t\tthis.position = &#39;left&#39;;\n\t\t\t\t}\n\n\t\t\t\tif (this.verticalPosition === &#39;bottom&#39; &amp;&amp; rect.bottom &gt; viewportHeight) {\n\t\t\t\t\tthis.verticalPosition = &#39;top&#39;;\n\t\t\t\t} else if (this.verticalPosition === &#39;top&#39; &amp;&amp; rect.top &lt; 0) {\n\t\t\t\t\tthis.verticalPosition = &#39;bottom&#39;;\n\t\t\t\t}\n\t\t\t}\n\t\t}\" @resize.window=\"if (open) updatePosition()\" data-position=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.Position)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 82, Col: 32}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><button type=\"button\" class=\"inline-flex justify-center w-full rounded-md border border-gray-300 dark:border-gray-600 shadow-sm px-4 py-2 bg-white dark:bg-gray-800 text-sm font-medium text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-indigo-400\" id=\"dropdown-menu-button\" @click=\"open = !open; if (open) $nextTick(() =&gt; updatePosition())\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 90, Col: 16}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <svg class=\"-mr-1 ml-2 h-5 w-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\"><path fill-rule=\"evenodd\" d=\"M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z\" clip-rule=\"evenodd\"></path></svg></button><div x-ref=\"menu\" x-show=\"open\" @click.away=\"open = false\" x-transition:enter=\"transition ease-out duration-100\" x-transition:enter-start=\"transform opacity-0 scale-95\" x-transition:enter-end=\"transform opacity-100 scale-100\" x-transition:leave=\"transition ease-in duration-75\" x-transition:leave-start=\"transform opacity-100 scale-100\" x-transition:leave-end=\"transform opacity-0 scale-95\" :class=\"{\n\t\t\t\t&#39;right-0&#39;: position === &#39;left&#39;,\n\t\t\t\t&#39;left-0&#39;: position !== &#39;left&#39;,\n\t\t\t\t&#39;bottom-full mb-2&#39;: verticalPosition === &#39;top&#39;,\n\t\t\t\t&#39;top-full mt-2&#39;: verticalPosition === &#39;bottom&#39;\n\t\t\t}\" class=\"absolute w-56 rounded-md shadow-lg bg-white dark:bg-gray-800 ring-1 ring-black ring-opacity-5 dark:ring-gray-700 focus:outline-none z-10\"><div class=\"py-1\" role=\"menu\" aria-orientation=\"vertical\" aria-labelledby=\"dropdown-menu-button\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, item := range props.Items {
if item.Href != "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 templ.SafeURL = templ.SafeURL(item.Href)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var6)))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" target=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(item.Target)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 118, Col: 27}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" class=\"block px-4 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white\" role=\"menuitem\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(item.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 121, Col: 19}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<button type=\"button\" class=\"block w-full text-left px-4 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white\" role=\"menuitem\" @click=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("$dispatch('dropdown-selected', { value: '%s' }); open = false", item.Value))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 127, Col: 104}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
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
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(item.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 128, Col: 19}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</button>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -658,6 +658,10 @@ body {
bottom: 0px;
}
.bottom-full {
bottom: 100%;
}
.left-0 {
left: 0px;
}
@ -670,6 +674,10 @@ body {
top: 0px;
}
.top-full {
top: 100%;
}
.z-10 {
z-index: 10;
}
@ -687,6 +695,10 @@ body {
margin-right: auto;
}
.-mr-1 {
margin-right: -0.25rem;
}
.mb-1 {
margin-bottom: 0.25rem;
}
@ -707,6 +719,10 @@ body {
margin-left: 0.25rem;
}
.ml-2 {
margin-left: 0.5rem;
}
.mr-2 {
margin-right: 0.5rem;
}
@ -827,6 +843,10 @@ body {
width: 1.25rem;
}
.w-56 {
width: 14rem;
}
.w-6 {
width: 1.5rem;
}
@ -897,6 +917,18 @@ body {
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));
}
.scale-100 {
--tw-scale-x: 1;
--tw-scale-y: 1;
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));
}
.scale-95 {
--tw-scale-x: .95;
--tw-scale-y: .95;
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));
}
.transform {
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));
}
@ -1065,6 +1097,11 @@ body {
border-color: hsl(var(--foreground) / var(--tw-border-opacity));
}
.border-gray-300 {
--tw-border-opacity: 1;
border-color: rgb(209 213 219 / var(--tw-border-opacity));
}
.border-input {
--tw-border-opacity: 1;
border-color: hsl(var(--input) / var(--tw-border-opacity));
@ -1126,6 +1163,11 @@ body {
background-color: hsl(var(--secondary) / var(--tw-bg-opacity));
}
.bg-white {
--tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.bg-opacity-50 {
--tw-bg-opacity: 0.5;
}
@ -1185,6 +1227,11 @@ body {
padding-right: 2rem;
}
.py-1 {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
}
.py-2 {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
@ -1404,6 +1451,21 @@ body {
outline-style: solid;
}
.ring-1 {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
}
.ring-black {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity));
}
.ring-opacity-5 {
--tw-ring-opacity: 0.05;
}
.ring-offset-background {
--tw-ring-offset-color: hsl(var(--background) / 1);
}
@ -1460,6 +1522,10 @@ body {
transition-duration: 300ms;
}
.duration-75 {
transition-duration: 75ms;
}
.ease-in {
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
}
@ -1518,6 +1584,11 @@ body {
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
}
.hover\:bg-gray-50:hover {
--tw-bg-opacity: 1;
background-color: rgb(249 250 251 / var(--tw-bg-opacity));
}
.hover\:bg-muted:hover {
--tw-bg-opacity: 1;
background-color: hsl(var(--muted) / var(--tw-bg-opacity));
@ -1546,6 +1617,11 @@ body {
color: rgb(107 114 128 / var(--tw-text-opacity));
}
.hover\:text-gray-900:hover {
--tw-text-opacity: 1;
color: rgb(17 24 39 / var(--tw-text-opacity));
}
.hover\:text-primary\/80:hover {
color: hsl(var(--primary) / 0.8);
}
@ -1578,6 +1654,10 @@ body {
--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity));
}
.focus\:ring-offset-2:focus {
--tw-ring-offset-width: 2px;
}
.focus-visible\:outline-none:focus-visible {
outline: 2px solid transparent;
outline-offset: 2px;
@ -1624,11 +1704,26 @@ body {
opacity: 1;
}
.dark\:border-gray-600:is(.dark *) {
--tw-border-opacity: 1;
border-color: rgb(75 85 99 / var(--tw-border-opacity));
}
.dark\:bg-gray-800:is(.dark *) {
--tw-bg-opacity: 1;
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
}
.dark\:text-gray-200:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(229 231 235 / var(--tw-text-opacity));
}
.dark\:ring-gray-700:is(.dark *) {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(55 65 81 / var(--tw-ring-opacity));
}
.dark\:file\:text-foreground:is(.dark *)::file-selector-button {
--tw-text-opacity: 1;
color: hsl(var(--foreground) / var(--tw-text-opacity));
@ -1639,6 +1734,16 @@ body {
background-color: rgb(55 65 81 / var(--tw-bg-opacity));
}
.dark\:hover\:text-white:hover:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.dark\:focus\:ring-indigo-400:focus:is(.dark *) {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(129 140 248 / var(--tw-ring-opacity));
}
@media (min-width: 640px) {
.sm\:my-8 {
margin-top: 2rem;