package homepage import ( "slices" "strings" "github.com/yusing/ds/ordered" "github.com/yusing/godoxy/internal/homepage/icons" "github.com/yusing/godoxy/internal/homepage/widgets" "github.com/yusing/godoxy/internal/serialization" strutils "github.com/yusing/goutils/strings" ) type ( HomepageMap struct { ordered.Map[string, *Category] } // @name HomepageItemsMap Homepage []*Category // @name HomepageItems Category struct { Items []*Item `json:"items"` Name string `json:"name"` } // @name HomepageCategory ItemConfig struct { Show bool `json:"show"` Name string `json:"name"` // display name Icon *icons.URL `json:"icon" swaggertype:"string"` Category string `json:"category" validate:"omitempty"` Description string `json:"description" aliases:"desc"` URL string `json:"url,omitempty"` Favorite bool `json:"favorite"` WidgetConfig *widgets.Config `json:"widget_config,omitempty" aliases:"widget" extensions:"x-nullable"` } // @name HomepageItemConfig Widget struct { Label string `json:"label"` Value string `json:"value"` } // @name HomepageItemWidget Item struct { ItemConfig SortOrder int `json:"sort_order"` // sort order in category FavSortOrder int `json:"fav_sort_order"` // sort order in favorite AllSortOrder int `json:"all_sort_order"` // sort order in all Clicks int `json:"clicks"` Widgets []Widget `json:"widgets,omitempty"` Alias string `json:"alias"` Provider string `json:"provider"` OriginURL string `json:"origin_url"` ContainerID string `json:"container_id,omitempty" extensions:"x-nullable"` } // @name HomepageItem SortMethod string // @name HomepageSortMethod ) const ( CategoryAll = "All" CategoryFavorites = "Favorites" CategoryHidden = "Hidden" CategoryOthers = "Others" ) const ( SortMethodClicks = "clicks" // @name HomepageSortMethodClicks SortMethodAlphabetical = "alphabetical" // @name HomepageSortMethodAlphabetical SortMethodCustom = "custom" // @name HomepageSortMethodCustom ) func init() { serialization.RegisterDefaultValueFactory(func() *ItemConfig { return &ItemConfig{ Show: true, } }) } func NewHomepageMap(total int) *HomepageMap { m := &HomepageMap{ Map: *ordered.NewMap[string, *Category](ordered.WithCapacity(10)), } m.Set(CategoryFavorites, &Category{ Items: make([]*Item, 0), // no capacity reserved for this category Name: CategoryFavorites, }) m.Set(CategoryAll, &Category{ Items: make([]*Item, 0, total), Name: CategoryAll, }) m.Set(CategoryHidden, &Category{ Items: make([]*Item, 0), Name: CategoryHidden, }) return m } func (cfg Item) GetOverride() Item { return overrideConfigInstance.GetOverride(cfg) } func (c *HomepageMap) Add(item *Item) { c.add(item, item.Category) // add to all category even if item is hidden c.add(item, CategoryAll) if item.Show { if item.Favorite { c.add(item, CategoryFavorites) } } else { c.add(item, CategoryHidden) } } func (c *HomepageMap) add(item *Item, categoryName string) { category := c.Get(categoryName) if category == nil { category = &Category{ Items: make([]*Item, 0), Name: categoryName, } c.Set(categoryName, category) } category.Items = append(category.Items, item) } func (c *Category) Sort(method SortMethod) { switch method { case SortMethodClicks: c.sortByClicks() case SortMethodAlphabetical: c.sortByAlphabetical() case SortMethodCustom: c.sortByCustom() } } func (c *Category) sortByClicks() { slices.SortStableFunc(c.Items, func(a, b *Item) int { if a.Clicks > b.Clicks { return -1 } if a.Clicks < b.Clicks { return 1 } // fallback to alphabetical return strings.Compare(strutils.Title(a.Name), strutils.Title(b.Name)) }) } func (c *Category) sortByAlphabetical() { slices.SortStableFunc(c.Items, func(a, b *Item) int { return strings.Compare(strutils.Title(a.Name), strutils.Title(b.Name)) }) } func (c *Category) sortByCustom() { switch c.Name { case CategoryFavorites: slices.SortStableFunc(c.Items, func(a, b *Item) int { if a.FavSortOrder < b.FavSortOrder { return -1 } if a.FavSortOrder > b.FavSortOrder { return 1 } return 0 }) case CategoryAll: slices.SortStableFunc(c.Items, func(a, b *Item) int { if a.AllSortOrder < b.AllSortOrder { return -1 } if a.AllSortOrder > b.AllSortOrder { return 1 } return 0 }) default: slices.SortStableFunc(c.Items, func(a, b *Item) int { if a.SortOrder < b.SortOrder { return -1 } if a.SortOrder > b.SortOrder { return 1 } return 0 }) } }