Skip to content

Commit da75b09

Browse files
POC: Use gomponents for Explore Users page
1 parent b0936f4 commit da75b09

File tree

17 files changed

+569
-4
lines changed

17 files changed

+569
-4
lines changed

components/components.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package components
2+
3+
import (
4+
"code.gitea.io/gitea/modules/svg"
5+
g "maragu.dev/gomponents"
6+
)
7+
8+
func If(condition bool, node g.Node) g.Node {
9+
if condition {
10+
return node
11+
}
12+
return nil
13+
}
14+
15+
func SVG(icon string, others ...any) g.Node {
16+
return g.Raw(string(svg.RenderHTML(icon)))
17+
}
18+
19+
// Utility to add "active" class if condition is true
20+
func classIf(condition bool, class string) string {
21+
if condition {
22+
return class
23+
}
24+
return ""
25+
}

components/explore_navbar.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package components
2+
3+
import (
4+
"code.gitea.io/gitea/models/unit"
5+
"code.gitea.io/gitea/modules/translation"
6+
g "maragu.dev/gomponents"
7+
gh "maragu.dev/gomponents/html"
8+
)
9+
10+
type ExploreNavbarProps struct {
11+
PageIsExploreRepositories bool
12+
UsersPageIsDisabled bool
13+
AppSubUrl string
14+
PageIsExploreUsers bool
15+
PageIsExploreCode bool
16+
IsRepoIndexerEnabled bool
17+
CodePageIsDisabled bool
18+
PageIsExploreOrganizations bool
19+
OrganizationsPageIsDisabled bool
20+
Locale translation.Locale
21+
}
22+
23+
func ExploreNavbar(data ExploreNavbarProps) g.Node {
24+
tr := func(key string) string {
25+
return string(data.Locale.Tr(key))
26+
}
27+
28+
isCodeGlobalDisabled := unit.TypeCode.UnitGlobalDisabled()
29+
30+
return g.El("overflow-menu",
31+
gh.Class("ui secondary pointing tabular top attached borderless menu secondary-nav"),
32+
gh.Div(
33+
gh.Class("overflow-menu-items tw-justify-center"),
34+
gh.A(
35+
gh.Class(classIf(data.PageIsExploreRepositories, "active ")+"item"),
36+
gh.Href(data.AppSubUrl+"/explore/repos"),
37+
SVG("octicon-repo"),
38+
g.Text(" "+tr("explore.repos")),
39+
),
40+
If(!data.UsersPageIsDisabled,
41+
gh.A(
42+
gh.Class(classIf(data.PageIsExploreUsers, "active ")+"item"),
43+
gh.Href(data.AppSubUrl+"/explore/users"),
44+
SVG("octicon-person"),
45+
g.Text(" "+tr("explore.users")),
46+
),
47+
),
48+
If(!data.OrganizationsPageIsDisabled,
49+
gh.A(
50+
gh.Class(classIf(data.PageIsExploreOrganizations, "active ")+"item"),
51+
gh.Href(data.AppSubUrl+"/explore/organizations"),
52+
SVG("octicon-organization"),
53+
g.Text(" "+tr("explore.organizations")),
54+
),
55+
),
56+
If(!isCodeGlobalDisabled && data.IsRepoIndexerEnabled && !data.CodePageIsDisabled,
57+
gh.A(
58+
gh.Class(classIf(data.PageIsExploreCode, "active ")+"item"),
59+
gh.Href(data.AppSubUrl+"/explore/code"),
60+
SVG("octicon-code"),
61+
g.Text(" "+tr("explore.code")),
62+
),
63+
),
64+
),
65+
)
66+
}

components/explore_search.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package components
2+
3+
import (
4+
g "maragu.dev/gomponents"
5+
gh "maragu.dev/gomponents/html"
6+
)
7+
8+
func ExploreSearchMenu(data ExploreUsersPageProps, pageIsExploreUsers bool) g.Node {
9+
// Corresponds to templates/explore/search.tmpl
10+
11+
tr := func(key string) string {
12+
return string(data.Locale.Tr(key))
13+
}
14+
15+
return g.Group([]g.Node{
16+
gh.Div(
17+
gh.Class("ui small secondary filter menu tw-items-center tw-mx-0"),
18+
gh.Form(
19+
gh.Class("ui form ignore-dirty tw-flex-1"),
20+
If(pageIsExploreUsers,
21+
SearchCombo(data.Locale, data.Keyword, tr("search.user_kind")),
22+
),
23+
If(!pageIsExploreUsers,
24+
SearchCombo(data.Locale, data.Keyword, tr("search.org_kind")),
25+
),
26+
),
27+
gh.Div(
28+
gh.Class("ui small dropdown type jump item tw-mr-0"),
29+
gh.Span(
30+
gh.Class("text"),
31+
g.Text(tr("repo.issues.filter_sort")),
32+
),
33+
SVG("octicon-triangle-down", 14, "dropdown icon"),
34+
gh.Div(
35+
gh.Class("menu"),
36+
SortOption(data, "newest", tr("repo.issues.filter_sort.latest")),
37+
SortOption(data, "oldest", tr("repo.issues.filter_sort.oldest")),
38+
SortOption(data, "alphabetically", tr("repo.issues.label.filter_sort.alphabetically")),
39+
SortOption(data, "reversealphabetically", tr("repo.issues.label.filter_sort.reverse_alphabetically")),
40+
),
41+
),
42+
),
43+
gh.Div(gh.Class("divider")),
44+
})
45+
}

components/explore_users_page.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package components
2+
3+
import (
4+
"code.gitea.io/gitea/models/user"
5+
"code.gitea.io/gitea/modules/translation"
6+
"code.gitea.io/gitea/services/context"
7+
g "maragu.dev/gomponents"
8+
gh "maragu.dev/gomponents/html"
9+
)
10+
11+
type ExploreUsersPageProps struct {
12+
Title string
13+
Locale translation.Locale
14+
Keyword string
15+
SortType string
16+
Users []*user.User
17+
// ContextUser *user.User
18+
Context *context.Context
19+
IsSigned bool
20+
}
21+
22+
func ExploreUsersPage(data ExploreUsersPageProps) g.Node {
23+
// pageIsExplore := true
24+
pageIsExploreUsers := true
25+
26+
head, err := data.Context.HTMLPartial(200, "base/head")
27+
if err != nil {
28+
panic("could not render head")
29+
}
30+
31+
footer, err := data.Context.HTMLPartial(200, "base/footer")
32+
if err != nil {
33+
panic("could not render footer")
34+
}
35+
36+
return g.Group([]g.Node{
37+
g.Raw(head),
38+
gh.Div(
39+
gh.Role("main"),
40+
gh.Aria("label", data.Title),
41+
gh.Class("page-content explore users"),
42+
ExploreNavbar(ExploreNavbarProps{
43+
Locale: data.Locale,
44+
PageIsExploreUsers: pageIsExploreUsers,
45+
}),
46+
gh.Div(
47+
gh.Class("ui container"),
48+
ExploreSearchMenu(data, true),
49+
UserList(UserListProps{
50+
// ContextUser: data.ContextUser,
51+
Context: data.Context,
52+
Users: data.Users,
53+
IsSigned: data.IsSigned,
54+
Locale: data.Locale,
55+
PageIsAdminUsers: false,
56+
}),
57+
// Pagination(data),
58+
),
59+
),
60+
g.Raw(footer),
61+
})
62+
}

components/search_button.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package components
2+
3+
import (
4+
g "maragu.dev/gomponents"
5+
gh "maragu.dev/gomponents/html"
6+
)
7+
8+
func SearchButton(disabled bool, tooltip string) g.Node {
9+
// Corresponds to templates/shared/search/button.tmpl
10+
11+
class := "ui icon button"
12+
if disabled {
13+
class += " disabled"
14+
}
15+
16+
btn := gh.Button(
17+
gh.Type("submit"),
18+
gh.Class(class),
19+
SVG("octicon-search", 16),
20+
)
21+
22+
if tooltip != "" {
23+
btn = gh.Button(
24+
gh.Type("submit"),
25+
gh.Class(class),
26+
g.Attr("data-tooltip-content", tooltip),
27+
SVG("octicon-search", 16),
28+
)
29+
}
30+
31+
return btn
32+
}

components/search_combo.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package components
2+
3+
import (
4+
"code.gitea.io/gitea/modules/translation"
5+
g "maragu.dev/gomponents"
6+
gh "maragu.dev/gomponents/html"
7+
)
8+
9+
func SearchCombo(locale translation.Locale, value, placeholder string) g.Node {
10+
// Corresponds to templates/shared/search/combo.tmpl
11+
12+
disabled := false
13+
return gh.Div(
14+
gh.Class("ui small fluid action input"),
15+
SearchInput(value, placeholder, disabled),
16+
// TODO SearchModeDropdown
17+
SearchButton(disabled, ""),
18+
)
19+
}

components/search_input.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package components
2+
3+
import (
4+
g "maragu.dev/gomponents"
5+
gh "maragu.dev/gomponents/html"
6+
)
7+
8+
func SearchInput(value, placeholder string, disabled bool) g.Node {
9+
// Corresponds to templates/shared/search/input.tmpl
10+
11+
return gh.Input(
12+
gh.Type("search"),
13+
gh.Name("q"),
14+
gh.MaxLength("255"),
15+
g.Attr("spellcheck", "false"),
16+
gh.Value(value),
17+
gh.Placeholder(placeholder),
18+
If(disabled, gh.Disabled()),
19+
)
20+
}

components/sort_option.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package components
2+
3+
import (
4+
"fmt"
5+
"net/url"
6+
7+
g "maragu.dev/gomponents"
8+
gh "maragu.dev/gomponents/html"
9+
)
10+
11+
func SortOption(data ExploreUsersPageProps, sortType, label string) g.Node {
12+
active := ""
13+
if data.SortType == sortType {
14+
active = "active "
15+
}
16+
return gh.A(
17+
gh.Class(active+"item"),
18+
gh.Href(fmt.Sprintf("?sort=%s&q=%s", sortType, url.QueryEscape(data.Keyword))),
19+
g.Text(label),
20+
)
21+
}

components/user_list.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package components
2+
3+
import (
4+
"code.gitea.io/gitea/models/user"
5+
"code.gitea.io/gitea/modules/setting"
6+
templates "code.gitea.io/gitea/modules/templates"
7+
"code.gitea.io/gitea/modules/translation"
8+
"code.gitea.io/gitea/services/context"
9+
g "maragu.dev/gomponents"
10+
gh "maragu.dev/gomponents/html"
11+
)
12+
13+
type UserListProps struct {
14+
Users []*user.User
15+
// ContextUser *user.User
16+
IsSigned bool
17+
PageIsAdminUsers bool
18+
Locale translation.Locale
19+
Context *context.Context
20+
}
21+
22+
func UserList(data UserListProps) g.Node {
23+
tr := func(key string, args ...any) string {
24+
return string(data.Locale.Tr(key, args...))
25+
}
26+
27+
if len(data.Users) == 0 {
28+
return gh.Div(
29+
gh.Class("flex-list"),
30+
gh.Div(
31+
gh.Class("flex-item"),
32+
g.Text(tr("search.no_results")),
33+
),
34+
)
35+
}
36+
37+
return gh.Div(
38+
gh.Class("flex-list"),
39+
g.Group(g.Map(data.Users, func(u *user.User) g.Node {
40+
utils := templates.NewAvatarUtils(data.Context)
41+
42+
return gh.Div(
43+
gh.Class("flex-item tw-items-center"),
44+
gh.Div(
45+
gh.Class("flex-item-leading"),
46+
g.Raw(string(utils.Avatar(u, 48))),
47+
),
48+
gh.Div(
49+
gh.Class("flex-item-main"),
50+
gh.Div(
51+
gh.Class("flex-item-title"),
52+
UserName(UserNameProps{
53+
Locale: data.Locale,
54+
User: u,
55+
}),
56+
If(u.Visibility.IsPrivate(),
57+
gh.Span(
58+
gh.Class("ui basic tiny label"),
59+
g.Text(tr("repo.desc.private")),
60+
),
61+
),
62+
),
63+
gh.Div(
64+
gh.Class("flex-item-body"),
65+
If(u.Location != "",
66+
gh.Span(
67+
gh.Class("flex-text-inline"),
68+
SVG("octicon-location", 16),
69+
g.Text(u.Location),
70+
),
71+
),
72+
If(u.Email != "" && (data.PageIsAdminUsers || (setting.UI.ShowUserEmail && data.IsSigned && !u.KeepEmailPrivate)),
73+
gh.Span(
74+
gh.Class("flex-text-inline"),
75+
SVG("octicon-mail", 16),
76+
gh.A(
77+
gh.Href("mailto:"+u.Email),
78+
g.Text(u.Email),
79+
),
80+
),
81+
),
82+
gh.Span(
83+
gh.Class("flex-text-inline"),
84+
SVG("octicon-calendar", 16),
85+
g.Raw(tr("user.joined_on", templates.NewDateUtils().AbsoluteShort(u.CreatedUnix))),
86+
),
87+
),
88+
),
89+
)
90+
})),
91+
)
92+
}

0 commit comments

Comments
 (0)