cleanup usage of orderedmap
add tests add groupby add groupbyordered
This commit is contained in:
parent
d44cd0b2ed
commit
cb012a4d82
12 changed files with 231 additions and 212 deletions
|
|
@ -1,82 +0,0 @@
|
||||||
package astgen
|
|
||||||
|
|
||||||
// OrderedMap is a generic data structure that maintains the order of keys.
|
|
||||||
type OrderedMap[K comparable, V any] struct {
|
|
||||||
keys []K
|
|
||||||
values map[K]V
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entries returns the key-value pairs in the order they were added.
|
|
||||||
func (om *OrderedMap[K, V]) Entries() []struct {
|
|
||||||
Key K
|
|
||||||
Value V
|
|
||||||
} {
|
|
||||||
entries := make([]struct {
|
|
||||||
Key K
|
|
||||||
Value V
|
|
||||||
}, len(om.keys))
|
|
||||||
for i, key := range om.keys {
|
|
||||||
entries[i] = struct {
|
|
||||||
Key K
|
|
||||||
Value V
|
|
||||||
}{
|
|
||||||
Key: key,
|
|
||||||
Value: om.values[key],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return entries
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewOrderedMap creates a new OrderedMap.
|
|
||||||
func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V] {
|
|
||||||
return &OrderedMap[K, V]{
|
|
||||||
keys: []K{},
|
|
||||||
values: make(map[K]V),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set adds or updates a key-value pair in the OrderedMap.
|
|
||||||
func (om *OrderedMap[K, V]) Set(key K, value V) {
|
|
||||||
// Check if the key already exists
|
|
||||||
if _, exists := om.values[key]; !exists {
|
|
||||||
om.keys = append(om.keys, key) // Append key to the keys slice if it's a new key
|
|
||||||
}
|
|
||||||
om.values[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get retrieves a value by key.
|
|
||||||
func (om *OrderedMap[K, V]) Get(key K) (V, bool) {
|
|
||||||
value, exists := om.values[key]
|
|
||||||
return value, exists
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keys returns the keys in the order they were added.
|
|
||||||
func (om *OrderedMap[K, V]) Keys() []K {
|
|
||||||
return om.keys
|
|
||||||
}
|
|
||||||
|
|
||||||
// Values returns the values in the order of their keys.
|
|
||||||
func (om *OrderedMap[K, V]) Values() []V {
|
|
||||||
values := make([]V, len(om.keys))
|
|
||||||
for i, key := range om.keys {
|
|
||||||
values[i] = om.values[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
return values
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete removes a key-value pair from the OrderedMap.
|
|
||||||
func (om *OrderedMap[K, V]) Delete(key K) {
|
|
||||||
if _, exists := om.values[key]; exists {
|
|
||||||
// Remove the key from the map
|
|
||||||
delete(om.values, key)
|
|
||||||
|
|
||||||
// Remove the key from the keys slice
|
|
||||||
for i, k := range om.keys {
|
|
||||||
if k == key {
|
|
||||||
om.keys = append(om.keys[:i], om.keys[i+1:]...)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -7,16 +7,3 @@ import (
|
||||||
func PanicF(format string, args ...interface{}) {
|
func PanicF(format string, args ...interface{}) {
|
||||||
panic(fmt.Sprintf(format, args...))
|
panic(fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func Unique[T any](slice []T, key func(item T) string) []T {
|
|
||||||
var result []T
|
|
||||||
seen := make(map[string]bool)
|
|
||||||
for _, v := range slice {
|
|
||||||
k := key(v)
|
|
||||||
if _, ok := seen[k]; !ok {
|
|
||||||
seen[k] = true
|
|
||||||
result = append(result, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,24 @@
|
||||||
package datastructures
|
package orderedmap
|
||||||
|
|
||||||
// OrderedMap is a generic data structure that maintains the order of keys.
|
|
||||||
type OrderedMap[K comparable, V any] struct {
|
|
||||||
keys []K
|
|
||||||
values map[K]V
|
|
||||||
}
|
|
||||||
|
|
||||||
type Entry[K comparable, V any] struct {
|
type Entry[K comparable, V any] struct {
|
||||||
Key K
|
Key K
|
||||||
Value V
|
Value V
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Map is a generic data structure that maintains the order of keys.
|
||||||
|
type Map[K comparable, V any] struct {
|
||||||
|
keys []K
|
||||||
|
values map[K]V
|
||||||
|
}
|
||||||
|
|
||||||
|
func (om *Map[K, V]) Each(cb func(key K, value V)) {
|
||||||
|
for _, key := range om.keys {
|
||||||
|
cb(key, om.values[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Entries returns the key-value pairs in the order they were added.
|
// Entries returns the key-value pairs in the order they were added.
|
||||||
func (om *OrderedMap[K, V]) Entries() []Entry[K, V] {
|
func (om *Map[K, V]) Entries() []Entry[K, V] {
|
||||||
entries := make([]Entry[K, V], len(om.keys))
|
entries := make([]Entry[K, V], len(om.keys))
|
||||||
for i, key := range om.keys {
|
for i, key := range om.keys {
|
||||||
entries[i] = Entry[K, V]{
|
entries[i] = Entry[K, V]{
|
||||||
|
|
@ -23,16 +29,16 @@ func (om *OrderedMap[K, V]) Entries() []Entry[K, V] {
|
||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOrderedMap creates a new OrderedMap.
|
// New creates a new Map.
|
||||||
func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V] {
|
func New[K comparable, V any]() *Map[K, V] {
|
||||||
return &OrderedMap[K, V]{
|
return &Map[K, V]{
|
||||||
keys: []K{},
|
keys: []K{},
|
||||||
values: make(map[K]V),
|
values: make(map[K]V),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set adds or updates a key-value pair in the OrderedMap.
|
// Set adds or updates a key-value pair in the Map.
|
||||||
func (om *OrderedMap[K, V]) Set(key K, value V) {
|
func (om *Map[K, V]) Set(key K, value V) {
|
||||||
// Check if the key already exists
|
// Check if the key already exists
|
||||||
if _, exists := om.values[key]; !exists {
|
if _, exists := om.values[key]; !exists {
|
||||||
om.keys = append(om.keys, key) // Append key to the keys slice if it's a new key
|
om.keys = append(om.keys, key) // Append key to the keys slice if it's a new key
|
||||||
|
|
@ -41,18 +47,18 @@ func (om *OrderedMap[K, V]) Set(key K, value V) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get retrieves a value by key.
|
// Get retrieves a value by key.
|
||||||
func (om *OrderedMap[K, V]) Get(key K) (V, bool) {
|
func (om *Map[K, V]) Get(key K) (V, bool) {
|
||||||
value, exists := om.values[key]
|
value, exists := om.values[key]
|
||||||
return value, exists
|
return value, exists
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keys returns the keys in the order they were added.
|
// Keys returns the keys in the order they were added.
|
||||||
func (om *OrderedMap[K, V]) Keys() []K {
|
func (om *Map[K, V]) Keys() []K {
|
||||||
return om.keys
|
return om.keys
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values returns the values in the order of their keys.
|
// Values returns the values in the order of their keys.
|
||||||
func (om *OrderedMap[K, V]) Values() []V {
|
func (om *Map[K, V]) Values() []V {
|
||||||
values := make([]V, len(om.keys))
|
values := make([]V, len(om.keys))
|
||||||
for i, key := range om.keys {
|
for i, key := range om.keys {
|
||||||
values[i] = om.values[key]
|
values[i] = om.values[key]
|
||||||
|
|
@ -61,8 +67,8 @@ func (om *OrderedMap[K, V]) Values() []V {
|
||||||
return values
|
return values
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete removes a key-value pair from the OrderedMap.
|
// Delete removes a key-value pair from the Map.
|
||||||
func (om *OrderedMap[K, V]) Delete(key K) {
|
func (om *Map[K, V]) Delete(key K) {
|
||||||
if _, exists := om.values[key]; exists {
|
if _, exists := om.values[key]; exists {
|
||||||
// Remove the key from the map
|
// Remove the key from the map
|
||||||
delete(om.values, key)
|
delete(om.values, key)
|
||||||
33
framework/datastructure/orderedmap/orderedmap_test.go
Normal file
33
framework/datastructure/orderedmap/orderedmap_test.go
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
package orderedmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOrderedMap(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
om := New[string, int]()
|
||||||
|
|
||||||
|
alphabet := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}
|
||||||
|
for index, letter := range alphabet {
|
||||||
|
om.Set(letter, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, alphabet, om.Keys())
|
||||||
|
|
||||||
|
c, ok := om.Get("c")
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, 2, c)
|
||||||
|
|
||||||
|
for i, entry := range om.Entries() {
|
||||||
|
if i == 5 {
|
||||||
|
assert.Equal(t, "f", entry.Key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
om.Delete("c")
|
||||||
|
value, ok := om.Get("c")
|
||||||
|
assert.False(t, ok)
|
||||||
|
assert.Equal(t, 0, value)
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
package h
|
package h
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/maddalax/htmgo/framework/datastructure/orderedmap"
|
||||||
|
)
|
||||||
|
|
||||||
// Unique returns a new slice with only unique items.
|
// Unique returns a new slice with only unique items.
|
||||||
func Unique[T any](slice []T, key func(item T) string) []T {
|
func Unique[T any](slice []T, key func(item T) string) []T {
|
||||||
var result []T
|
var result []T
|
||||||
|
|
@ -14,6 +18,7 @@ func Unique[T any](slice []T, key func(item T) string) []T {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find returns the first item in the slice that matches the predicate.
|
||||||
func Find[T any](slice []T, predicate func(item *T) bool) *T {
|
func Find[T any](slice []T, predicate func(item *T) bool) *T {
|
||||||
for _, v := range slice {
|
for _, v := range slice {
|
||||||
if predicate(&v) {
|
if predicate(&v) {
|
||||||
|
|
@ -23,6 +28,34 @@ func Find[T any](slice []T, predicate func(item *T) bool) *T {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GroupBy groups the items in the slice by the key returned by the key function.
|
||||||
|
func GroupBy[T any, K comparable](slice []T, key func(item T) K) map[K][]T {
|
||||||
|
grouped := make(map[K][]T)
|
||||||
|
for _, item := range slice {
|
||||||
|
k := key(item)
|
||||||
|
items, ok := grouped[k]
|
||||||
|
if !ok {
|
||||||
|
items = []T{}
|
||||||
|
}
|
||||||
|
grouped[k] = append(items, item)
|
||||||
|
}
|
||||||
|
return grouped
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupByOrdered groups the items in the slice by the key returned by the key function, and returns an Map.
|
||||||
|
func GroupByOrdered[T any, K comparable](slice []T, key func(item T) K) *orderedmap.Map[K, []T] {
|
||||||
|
grouped := orderedmap.New[K, []T]()
|
||||||
|
for _, item := range slice {
|
||||||
|
k := key(item)
|
||||||
|
items, ok := grouped.Get(k)
|
||||||
|
if !ok {
|
||||||
|
items = []T{}
|
||||||
|
}
|
||||||
|
grouped.Set(k, append(items, item))
|
||||||
|
}
|
||||||
|
return grouped
|
||||||
|
}
|
||||||
|
|
||||||
// Filter returns a new slice with only items that match the predicate.
|
// Filter returns a new slice with only items that match the predicate.
|
||||||
func Filter[T any](slice []T, predicate func(item T) bool) []T {
|
func Filter[T any](slice []T, predicate func(item T) bool) []T {
|
||||||
var result []T
|
var result []T
|
||||||
|
|
|
||||||
102
framework/h/array_test.go
Normal file
102
framework/h/array_test.go
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
package h
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUnique(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
slice := []string{"a", "b", "b", "c", "d", "d", "x"}
|
||||||
|
unique := Unique(slice, func(item string) string {
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
assert.Equal(t, []string{"a", "b", "c", "d", "x"}, unique)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilter(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
slice := []string{"a", "b", "b", "c", "d", "d", "x"}
|
||||||
|
filtered := Filter(slice, func(item string) bool {
|
||||||
|
return item == "b"
|
||||||
|
})
|
||||||
|
assert.Equal(t, []string{"b", "b"}, filtered)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMap(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
slice := []string{"a", "b", "c"}
|
||||||
|
mapped := Map(slice, func(item string) string {
|
||||||
|
return strings.ToUpper(item)
|
||||||
|
})
|
||||||
|
assert.Equal(t, []string{"A", "B", "C"}, mapped)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGroupBy(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
type Item struct {
|
||||||
|
Name string
|
||||||
|
Job string
|
||||||
|
}
|
||||||
|
|
||||||
|
items := []Item{
|
||||||
|
{Name: "Alice", Job: "Developer"},
|
||||||
|
{Name: "Bob", Job: "Designer"},
|
||||||
|
{Name: "Charlie", Job: "Developer"},
|
||||||
|
{Name: "David", Job: "Designer"},
|
||||||
|
{Name: "Eve", Job: "Developer"},
|
||||||
|
{Name: "Frank", Job: "Product Manager"},
|
||||||
|
}
|
||||||
|
|
||||||
|
grouped := GroupBy(items, func(item Item) string {
|
||||||
|
return item.Job
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.Equal(t, 3, len(grouped))
|
||||||
|
assert.Equal(t, 3, len(grouped["Developer"]))
|
||||||
|
assert.Equal(t, 2, len(grouped["Designer"]))
|
||||||
|
assert.Equal(t, 1, len(grouped["Product Manager"]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGroupByOrdered(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
type Item struct {
|
||||||
|
Name string
|
||||||
|
Job string
|
||||||
|
}
|
||||||
|
|
||||||
|
items := []Item{
|
||||||
|
{Name: "Alice", Job: "Developer"},
|
||||||
|
{Name: "Bob", Job: "Designer"},
|
||||||
|
{Name: "Charlie", Job: "Developer"},
|
||||||
|
{Name: "David", Job: "Designer"},
|
||||||
|
{Name: "Eve", Job: "Developer"},
|
||||||
|
{Name: "Frank", Job: "Product Manager"},
|
||||||
|
}
|
||||||
|
|
||||||
|
grouped := GroupByOrdered(items, func(item Item) string {
|
||||||
|
return item.Job
|
||||||
|
})
|
||||||
|
|
||||||
|
keys := []string{"Developer", "Designer", "Product Manager"}
|
||||||
|
assert.Equal(t, keys, grouped.Keys())
|
||||||
|
|
||||||
|
devs, ok := grouped.Get("Developer")
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, 3, len(devs))
|
||||||
|
assert.Equal(t, "Alice", devs[0].Name)
|
||||||
|
assert.Equal(t, "Charlie", devs[1].Name)
|
||||||
|
assert.Equal(t, "Eve", devs[2].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFind(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
slice := []string{"a", "b", "c"}
|
||||||
|
found := Find(slice, func(item *string) bool {
|
||||||
|
return *item == "b"
|
||||||
|
})
|
||||||
|
assert.Equal(t, "b", *found)
|
||||||
|
}
|
||||||
|
|
@ -2,16 +2,15 @@ package h
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"github.com/maddalax/htmgo/framework/datastructure/orderedmap"
|
||||||
|
|
||||||
"github.com/maddalax/htmgo/framework/hx"
|
"github.com/maddalax/htmgo/framework/hx"
|
||||||
"github.com/maddalax/htmgo/framework/internal/datastructure"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AttributeMap = map[string]any
|
type AttributeMap = map[string]any
|
||||||
|
|
||||||
type AttributeMapOrdered struct {
|
type AttributeMapOrdered struct {
|
||||||
data *datastructure.OrderedMap[string, string]
|
data *orderedmap.Map[string, string]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *AttributeMapOrdered) Set(key string, value any) {
|
func (m *AttributeMapOrdered) Set(key string, value any) {
|
||||||
|
|
@ -39,12 +38,12 @@ func (m *AttributeMapOrdered) Each(cb func(key string, value string)) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *AttributeMapOrdered) Entries() []datastructure.MapEntry[string, string] {
|
func (m *AttributeMapOrdered) Entries() []orderedmap.Entry[string, string] {
|
||||||
return m.data.Entries()
|
return m.data.Entries()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAttributeMap(pairs ...string) *AttributeMapOrdered {
|
func NewAttributeMap(pairs ...string) *AttributeMapOrdered {
|
||||||
m := datastructure.NewOrderedMap[string, string]()
|
m := orderedmap.New[string, string]()
|
||||||
if len(pairs)%2 == 0 {
|
if len(pairs)%2 == 0 {
|
||||||
for i := 0; i < len(pairs); i++ {
|
for i := 0; i < len(pairs); i++ {
|
||||||
m.Set(pairs[i], pairs[i+1])
|
m.Set(pairs[i], pairs[i+1])
|
||||||
|
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
package datastructure
|
|
||||||
|
|
||||||
type MapEntry[K comparable, V any] struct {
|
|
||||||
Key K
|
|
||||||
Value V
|
|
||||||
}
|
|
||||||
|
|
||||||
// OrderedMap is a generic data structure that maintains the order of keys.
|
|
||||||
type OrderedMap[K comparable, V any] struct {
|
|
||||||
keys []K
|
|
||||||
values map[K]V
|
|
||||||
}
|
|
||||||
|
|
||||||
func (om *OrderedMap[K, V]) Each(cb func(key K, value V)) {
|
|
||||||
for _, key := range om.keys {
|
|
||||||
cb(key, om.values[key])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entries returns the key-value pairs in the order they were added.
|
|
||||||
func (om *OrderedMap[K, V]) Entries() []MapEntry[K, V] {
|
|
||||||
entries := make([]MapEntry[K, V], len(om.keys))
|
|
||||||
for i, key := range om.keys {
|
|
||||||
entries[i] = MapEntry[K, V]{
|
|
||||||
Key: key,
|
|
||||||
Value: om.values[key],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return entries
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewOrderedMap creates a new OrderedMap.
|
|
||||||
func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V] {
|
|
||||||
return &OrderedMap[K, V]{
|
|
||||||
keys: []K{},
|
|
||||||
values: make(map[K]V),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set adds or updates a key-value pair in the OrderedMap.
|
|
||||||
func (om *OrderedMap[K, V]) Set(key K, value V) {
|
|
||||||
// Check if the key already exists
|
|
||||||
if _, exists := om.values[key]; !exists {
|
|
||||||
om.keys = append(om.keys, key) // Append key to the keys slice if it's a new key
|
|
||||||
}
|
|
||||||
om.values[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get retrieves a value by key.
|
|
||||||
func (om *OrderedMap[K, V]) Get(key K) (V, bool) {
|
|
||||||
value, exists := om.values[key]
|
|
||||||
return value, exists
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keys returns the keys in the order they were added.
|
|
||||||
func (om *OrderedMap[K, V]) Keys() []K {
|
|
||||||
return om.keys
|
|
||||||
}
|
|
||||||
|
|
||||||
// Values returns the values in the order of their keys.
|
|
||||||
func (om *OrderedMap[K, V]) Values() []V {
|
|
||||||
values := make([]V, len(om.keys))
|
|
||||||
for i, key := range om.keys {
|
|
||||||
values[i] = om.values[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
return values
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete removes a key-value pair from the OrderedMap.
|
|
||||||
func (om *OrderedMap[K, V]) Delete(key K) {
|
|
||||||
if _, exists := om.values[key]; exists {
|
|
||||||
// Remove the key from the map
|
|
||||||
delete(om.values, key)
|
|
||||||
|
|
||||||
// Remove the key from the keys slice
|
|
||||||
for i, k := range om.keys {
|
|
||||||
if k == key {
|
|
||||||
om.keys = append(om.keys[:i], om.keys[i+1:]...)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -10,6 +10,7 @@ type Snippet struct {
|
||||||
partial h.PartialFunc
|
partial h.PartialFunc
|
||||||
externalRoute string
|
externalRoute string
|
||||||
sourceCodePath string
|
sourceCodePath string
|
||||||
|
category string
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetSnippet(ctx *h.RequestContext, snippet *Snippet) {
|
func SetSnippet(ctx *h.RequestContext, snippet *Snippet) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package examples
|
||||||
import "htmgo-site/partials/snippets"
|
import "htmgo-site/partials/snippets"
|
||||||
|
|
||||||
var FormWithLoadingStateSnippet = Snippet{
|
var FormWithLoadingStateSnippet = Snippet{
|
||||||
|
category: "Forms",
|
||||||
name: "Form",
|
name: "Form",
|
||||||
description: "A simple form submission example with a loading state",
|
description: "A simple form submission example with a loading state",
|
||||||
sidebarName: "Form With Loading State",
|
sidebarName: "Form With Loading State",
|
||||||
|
|
@ -11,6 +12,7 @@ var FormWithLoadingStateSnippet = Snippet{
|
||||||
}
|
}
|
||||||
|
|
||||||
var UserAuthSnippet = Snippet{
|
var UserAuthSnippet = Snippet{
|
||||||
|
category: "Projects",
|
||||||
name: "User Authentication",
|
name: "User Authentication",
|
||||||
description: "An example showing basic user registration and login with htmgo",
|
description: "An example showing basic user registration and login with htmgo",
|
||||||
sidebarName: "User Authentication",
|
sidebarName: "User Authentication",
|
||||||
|
|
@ -20,6 +22,7 @@ var UserAuthSnippet = Snippet{
|
||||||
}
|
}
|
||||||
|
|
||||||
var ChatSnippet = Snippet{
|
var ChatSnippet = Snippet{
|
||||||
|
category: "Projects",
|
||||||
name: "Chat App",
|
name: "Chat App",
|
||||||
description: "A simple chat application built with htmgo using SSE for real-time updates",
|
description: "A simple chat application built with htmgo using SSE for real-time updates",
|
||||||
sidebarName: "Chat App Using SSE",
|
sidebarName: "Chat App Using SSE",
|
||||||
|
|
@ -29,6 +32,7 @@ var ChatSnippet = Snippet{
|
||||||
}
|
}
|
||||||
|
|
||||||
var HackerNewsSnippet = Snippet{
|
var HackerNewsSnippet = Snippet{
|
||||||
|
category: "Projects",
|
||||||
name: "HackerNews Clone",
|
name: "HackerNews Clone",
|
||||||
description: "A hacker news reader clone built with htmgo",
|
description: "A hacker news reader clone built with htmgo",
|
||||||
sidebarName: "HackerNews Clone",
|
sidebarName: "HackerNews Clone",
|
||||||
|
|
@ -38,6 +42,7 @@ var HackerNewsSnippet = Snippet{
|
||||||
}
|
}
|
||||||
|
|
||||||
var HtmgoSiteSnippet = Snippet{
|
var HtmgoSiteSnippet = Snippet{
|
||||||
|
category: "Projects",
|
||||||
name: "Htmgo Doc Site",
|
name: "Htmgo Doc Site",
|
||||||
description: "The htmgo site built with htmgo, recursion am I right?",
|
description: "The htmgo site built with htmgo, recursion am I right?",
|
||||||
sidebarName: "Htmgo Doc Site",
|
sidebarName: "Htmgo Doc Site",
|
||||||
|
|
@ -47,6 +52,7 @@ var HtmgoSiteSnippet = Snippet{
|
||||||
}
|
}
|
||||||
|
|
||||||
var TodoListSnippet = Snippet{
|
var TodoListSnippet = Snippet{
|
||||||
|
category: "Projects",
|
||||||
name: "Todo List",
|
name: "Todo List",
|
||||||
description: "A todo list built with htmgo",
|
description: "A todo list built with htmgo",
|
||||||
sidebarName: "Todo List",
|
sidebarName: "Todo List",
|
||||||
|
|
@ -56,6 +62,7 @@ var TodoListSnippet = Snippet{
|
||||||
}
|
}
|
||||||
|
|
||||||
var ClickToEditSnippet = Snippet{
|
var ClickToEditSnippet = Snippet{
|
||||||
|
category: "Forms",
|
||||||
name: "Inline Click To Edit",
|
name: "Inline Click To Edit",
|
||||||
description: "List view of items with a click to edit button and persistence",
|
description: "List view of items with a click to edit button and persistence",
|
||||||
sidebarName: "Inline Click To Edit",
|
sidebarName: "Inline Click To Edit",
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,16 @@
|
||||||
package examples
|
package examples
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/maddalax/htmgo/framework/datastructure/orderedmap"
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
"github.com/maddalax/htmgo/framework/h"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SnippetSidebar() *h.Element {
|
func SnippetSidebar() *h.Element {
|
||||||
|
|
||||||
|
grouped := h.GroupByOrdered(examples, func(example Snippet) string {
|
||||||
|
return example.category
|
||||||
|
})
|
||||||
|
|
||||||
return h.Div(
|
return h.Div(
|
||||||
h.Class("px-3 py-2 pr-6 md:min-h-screen pb-4 mb:pb-0 bg-neutral-50 border-r border-r-slate-300 overflow-y-auto"),
|
h.Class("px-3 py-2 pr-6 md:min-h-screen pb-4 mb:pb-0 bg-neutral-50 border-r border-r-slate-300 overflow-y-auto"),
|
||||||
h.Div(
|
h.Div(
|
||||||
|
|
@ -18,7 +24,15 @@ func SnippetSidebar() *h.Element {
|
||||||
),
|
),
|
||||||
h.Div(
|
h.Div(
|
||||||
h.Class("flex flex-col gap-2"),
|
h.Class("flex flex-col gap-2"),
|
||||||
h.List(examples, func(entry Snippet, index int) *h.Element {
|
h.List(grouped.Entries(), func(entry orderedmap.Entry[string, []Snippet], index int) *h.Element {
|
||||||
|
return h.Div(
|
||||||
|
h.P(
|
||||||
|
h.Text(entry.Key),
|
||||||
|
h.Class("text-slate-800 font-bold"),
|
||||||
|
),
|
||||||
|
h.Div(
|
||||||
|
h.Class("pl-4 flex flex-col"),
|
||||||
|
h.List(entry.Value, func(entry Snippet, index int) *h.Element {
|
||||||
return h.A(
|
return h.A(
|
||||||
h.Href(entry.path),
|
h.Href(entry.path),
|
||||||
h.Text(entry.sidebarName),
|
h.Text(entry.sidebarName),
|
||||||
|
|
@ -26,6 +40,9 @@ func SnippetSidebar() *h.Element {
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package partials
|
package partials
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/maddalax/htmgo/framework/datastructure/orderedmap"
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
"github.com/maddalax/htmgo/framework/h"
|
||||||
"htmgo-site/internal/datastructures"
|
|
||||||
"htmgo-site/internal/dirwalk"
|
"htmgo-site/internal/dirwalk"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
@ -37,8 +37,8 @@ func partsToName(parts []string) string {
|
||||||
return builder.String()
|
return builder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func groupByFirstPart(pages []*dirwalk.Page) *datastructures.OrderedMap[string, []*dirwalk.Page] {
|
func groupByFirstPart(pages []*dirwalk.Page) *orderedmap.Map[string, []*dirwalk.Page] {
|
||||||
grouped := datastructures.NewOrderedMap[string, []*dirwalk.Page]()
|
grouped := orderedmap.New[string, []*dirwalk.Page]()
|
||||||
for _, page := range pages {
|
for _, page := range pages {
|
||||||
if len(page.Parts) > 0 {
|
if len(page.Parts) > 0 {
|
||||||
section := page.Parts[0]
|
section := page.Parts[0]
|
||||||
|
|
@ -69,7 +69,7 @@ func DocSidebar(pages []*dirwalk.Page) *h.Element {
|
||||||
),
|
),
|
||||||
h.Div(
|
h.Div(
|
||||||
h.Class("flex flex-col gap-4"),
|
h.Class("flex flex-col gap-4"),
|
||||||
h.List(grouped.Entries(), func(entry datastructures.Entry[string, []*dirwalk.Page], index int) *h.Element {
|
h.List(grouped.Entries(), func(entry orderedmap.Entry[string, []*dirwalk.Page], index int) *h.Element {
|
||||||
return h.Div(
|
return h.Div(
|
||||||
h.P(
|
h.P(
|
||||||
h.Text(formatPart(entry.Key)),
|
h.Text(formatPart(entry.Key)),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue