diff --git a/docs/docsrc/examples/examples_presets/menu.go b/docs/docsrc/examples/examples_presets/menu.go index 3347f9d25..1ea87bdf1 100644 --- a/docs/docsrc/examples/examples_presets/menu.go +++ b/docs/docsrc/examples/examples_presets/menu.go @@ -1,6 +1,7 @@ package examples_presets import ( + "fmt" "net/http" "net/url" @@ -220,3 +221,40 @@ func PresetsGroupMenuWithPermission(b *presets.Builder, db *gorm.DB) ( // @snippet_end return } + +func PresetsMenuComponent(b *presets.Builder, db *gorm.DB) ( + mb *presets.ModelBuilder, + cl *presets.ListingBuilder, + ce *presets.EditingBuilder, + dp *presets.DetailingBuilder, +) { + PresetsGroupMenu(b, db) + b.MenuComponentFunc(func(menus []h.HTMLComponent, menuGroupSelected, menuItemSelected string) h.HTMLComponent { + return h.Div( + web.Scope( + vuetify.VList(menus...). + OpenStrategy("multiple"). + Class("primary--text"). + Density(vuetify.DensityCompact). + Attr("v-model:opened", "locals.menuOpened"). + Attr("v-model:selected", "locals.selection"). + Attr("color", "transparent"), + ).VSlot("{ locals }").Init( + fmt.Sprintf(`{ menuOpened: [%q] }`, menuGroupSelected), + fmt.Sprintf(`{ selection: [%q] }`, menuItemSelected), + ), + ) + }) + b.MenuOrder( + "books", + b.MenuGroup("Media1").SubItems( + "videos", + "musics", + ).Icon("mdi-video"), + b.MenuGroup("Media2").SubItems( + "videos", + "musics", + ).Icon("mdi-video"), + ) + return +} diff --git a/docs/docsrc/examples/examples_presets/menu_test.go b/docs/docsrc/examples/examples_presets/menu_test.go index bbbe68eb9..a40581b34 100644 --- a/docs/docsrc/examples/examples_presets/menu_test.go +++ b/docs/docsrc/examples/examples_presets/menu_test.go @@ -59,3 +59,28 @@ func TestPresetsCustomizeMenuWithPermission(t *testing.T) { }) } } + +func TestPresetsPresetsMenuComponent(t *testing.T) { + pb := presets.New().DataOperator(gorm2op.DataOperator(TestDB)) + PresetsMenuComponent(pb, TestDB) + + cases := []multipartestutils.TestCase{ + { + Name: "multiple openStrategy", + Debug: false, + ReqFunc: func() *http.Request { + return multipartestutils.NewMultipartBuilder(). + PageURL("/presets-menu-component/books"). + BuildEventFuncRequest() + }, + ExpectPageBodyContainsInOrder: []string{`:open-strategy='"multiple"'`}, + ExpectPageBodyNotContains: []string{`:open-strategy='"single"'`}, + }, + } + + for _, c := range cases { + t.Run(c.Name, func(t *testing.T) { + multipartestutils.RunCase(t, c, pb) + }) + } +} diff --git a/docs/docsrc/examples/examples_presets/mux.go b/docs/docsrc/examples/examples_presets/mux.go index 154b55b3d..661397134 100644 --- a/docs/docsrc/examples/examples_presets/mux.go +++ b/docs/docsrc/examples/examples_presets/mux.go @@ -41,6 +41,7 @@ func SamplesHandler(mux examples.Muxer) { addExample(mux, db, PresetsCustomizeMenu) addExample(mux, db, PresetsGroupMenu) addExample(mux, db, PresetsGroupMenuWithPermission) + addExample(mux, db, PresetsMenuComponent) addExample(mux, db, PresetsConfirmDialog) addExample(mux, db, PresetsEditingCustomizationTabs) addExample(mux, db, PresetsEditingValidate) diff --git a/presets/menu_order.go b/presets/menu_order.go index f379351f2..018661bef 100644 --- a/presets/menu_order.go +++ b/presets/menu_order.go @@ -16,9 +16,10 @@ import ( type MenuOrderBuilder struct { p *Builder // string or *MenuGroupBuilder - order []interface{} - modelMap map[string]*ModelBuilder - once sync.Once + order []interface{} + modelMap map[string]*ModelBuilder + menuComponentFunc func(menus []h.HTMLComponent, menuGroupSelected, menuItemSelected string) h.HTMLComponent + once sync.Once } type menuOrderItem struct { @@ -30,6 +31,11 @@ func NewMenuOrderBuilder(b *Builder) *MenuOrderBuilder { return &MenuOrderBuilder{p: b} } +func (b *MenuOrderBuilder) MenuComponentFunc(fn func(menus []h.HTMLComponent, menuGroupSelected, menuItemSelected string) h.HTMLComponent) *MenuOrderBuilder { + b.menuComponentFunc = fn + return b +} + func (b *MenuOrderBuilder) isMenuGroupInOrder(mgb *MenuGroupBuilder) bool { for _, v := range b.order { if v == mgb { @@ -208,6 +214,9 @@ func (b *MenuOrderBuilder) getActiveMenuState(ctx *web.EventContext, inOrderMap } func (b *MenuOrderBuilder) buildMenuComponent(menus []h.HTMLComponent, menuGroupSelected, menuItemSelected string) h.HTMLComponent { + if b.menuComponentFunc != nil { + return b.menuComponentFunc(menus, menuGroupSelected, menuItemSelected) + } return h.Div( web.Scope( VList(menus...). diff --git a/presets/presets.go b/presets/presets.go index ac47aa82c..9eed461c7 100644 --- a/presets/presets.go +++ b/presets/presets.go @@ -526,6 +526,11 @@ func (b *Builder) AddMenuTopItemFunc(key string, v ComponentFunc) (r *Builder) { return b } +func (b *Builder) MenuComponentFunc(fn func(menus []h.HTMLComponent, menuGroupSelected, menuItemSelected string) h.HTMLComponent) (r *Builder) { + b.menuOrder.menuComponentFunc = fn + return b +} + func (b *Builder) RunSwitchLocalCodeFunc(ctx *web.EventContext) (r h.HTMLComponent) { if b.switchLocaleFunc != nil { return b.switchLocaleFunc(ctx)