2
0

feat(org): Always show Overview tab with empty states

- Overview tab now always visible for organizations
- Added nice empty state for pinned repos with setup instructions
- Added empty state for public members section
- Added empty state for profile README with create button
- Added organization activity stats section
- Overview is now the default tab (not repositories)
- Added 10 new locale strings for empty states

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-11 01:56:20 +00:00
parent 72a540c8db
commit 521abad9b1
4 changed files with 206 additions and 112 deletions

View File

@@ -3781,5 +3781,15 @@
"git.filemode.normal_file": "Normal file",
"git.filemode.executable_file": "Executable file",
"git.filemode.symbolic_link": "Symbolic link",
"git.filemode.submodule": "Submodule"
}
"git.filemode.submodule": "Submodule",
"org.pinned_repos_empty_title": "Showcase your best work",
"org.pinned_repos_empty_desc": "Pin up to 6 repositories to highlight your organization's most important projects.",
"org.settings.pinned.manage": "Manage Pins",
"org.settings.pinned.setup": "Set Up Pinned Repos",
"org.no_public_members": "No public members yet",
"org.profile_readme_empty_title": "Add a profile README",
"org.profile_readme_empty_desc": "Create a .profile repository with a README.md to introduce your organization.",
"org.create_profile_repo": "Create Profile Repository",
"org.activity": "Activity",
"org.repositories": "Repositories"
}

View File

@@ -157,12 +157,10 @@ func home(ctx *context.Context, viewRepositories bool) {
}
ctx.Data["OrgStats"] = orgStats
// if no profile readme, it still means "view repositories"
isViewOverview := !viewRepositories && prepareOrgProfileReadme(ctx, prepareResult)
// Also show overview if there are pinned repos even without profile readme
if !viewRepositories && len(pinnedRepos) > 0 {
isViewOverview = true
}
// Always show overview by default for organizations
isViewOverview := !viewRepositories
// Load profile readme if available
prepareOrgProfileReadme(ctx, prepareResult)
ctx.Data["PageIsViewRepositories"] = !isViewOverview
ctx.Data["PageIsViewOverview"] = isViewOverview
ctx.Data["ShowOrgProfileReadmeSelector"] = isViewOverview && prepareResult.ProfilePublicReadmeBlob != nil && prepareResult.ProfilePrivateReadmeBlob != nil

View File

@@ -5,118 +5,206 @@
<div class="ui container">
<div class="ui mobile reversed stackable grid">
<div class="ui {{if .ShowMemberAndTeamTab}}eleven wide{{end}} column">
{{/* Profile README Section */}}
{{if .ProfileReadmeContent}}
<div id="readme_profile" class="render-content markup" data-profile-view-as-member="{{.IsViewingOrgAsMember}}">{{.ProfileReadmeContent}}</div>
{{end}}
{{/* Pinned Repositories Section */}}
{{if and .PageIsViewOverview .HasPinnedRepos}}
<div class="ui segment pinned-repos-section">
<h4 class="ui header">
{{svg "octicon-pin" 16}} {{ctx.Locale.Tr "org.pinned_repos"}}
</h4>
{{/* Ungrouped pinned repos */}}
{{if .UngroupedPinned}}
<div class="ui three stackable cards pinned-repos">
{{range .UngroupedPinned}}
{{if .Repo}}
<a class="ui card" href="{{.Repo.Link}}">
<div class="content">
<div class="header text truncate">
{{if .Repo.IsPrivate}}{{svg "octicon-lock" 16}}{{else if .Repo.IsFork}}{{svg "octicon-repo-forked" 16}}{{else if .Repo.IsMirror}}{{svg "octicon-mirror" 16}}{{else}}{{svg "octicon-repo" 16}}{{end}}
{{.Repo.Name}}
</div>
{{if .Repo.Description}}
<div class="description text truncate">{{.Repo.Description}}</div>
{{end}}
</div>
<div class="extra content">
{{if .Repo.PrimaryLanguage}}
<span class="tw-mr-2">
<span class="repo-language-color" style="background-color: {{.Repo.PrimaryLanguage.Color}}"></span>
{{.Repo.PrimaryLanguage.Language}}
</span>
{{end}}
{{if .Repo.NumStars}}
<span class="tw-mr-2">{{svg "octicon-star" 14}} {{.Repo.NumStars}}</span>
{{end}}
{{if .Repo.NumForks}}
<span>{{svg "octicon-repo-forked" 14}} {{.Repo.NumForks}}</span>
{{end}}
</div>
</a>
{{end}}
{{end}}
</div>
{{end}}
{{/* Grouped pinned repos */}}
{{range .PinnedGroups}}
{{$groupRepos := index $.PinnedByGroup .ID}}
{{if $groupRepos}}
<div class="pinned-group tw-mt-4">
<h5 class="ui header tw-mb-2">
{{svg "octicon-chevron-down" 14}} {{.Name}}
</h5>
<div class="ui three stackable cards pinned-repos">
{{range $groupRepos}}
{{if .Repo}}
<a class="ui card" href="{{.Repo.Link}}">
<div class="content">
<div class="header text truncate">
{{if .Repo.IsPrivate}}{{svg "octicon-lock" 16}}{{else if .Repo.IsFork}}{{svg "octicon-repo-forked" 16}}{{else if .Repo.IsMirror}}{{svg "octicon-mirror" 16}}{{else}}{{svg "octicon-repo" 16}}{{end}}
{{.Repo.Name}}
</div>
{{if .Repo.Description}}
<div class="description text truncate">{{.Repo.Description}}</div>
{{end}}
</div>
<div class="extra content">
{{if .Repo.PrimaryLanguage}}
<span class="tw-mr-2">
<span class="repo-language-color" style="background-color: {{.Repo.PrimaryLanguage.Color}}"></span>
{{.Repo.PrimaryLanguage.Language}}
</span>
{{end}}
{{if .Repo.NumStars}}
<span class="tw-mr-2">{{svg "octicon-star" 14}} {{.Repo.NumStars}}</span>
{{end}}
{{if .Repo.NumForks}}
<span>{{svg "octicon-repo-forked" 14}} {{.Repo.NumForks}}</span>
{{end}}
</div>
{{/* Overview Tab Content */}}
{{if .PageIsViewOverview}}
{{/* Pinned Repositories Section */}}
<div class="ui segment pinned-repos-section">
<h4 class="ui header tw-flex tw-items-center">
{{svg "octicon-pin" 16}} {{ctx.Locale.Tr "org.pinned_repos"}}
{{if .IsOrganizationOwner}}
<a class="tw-ml-auto ui mini button" href="{{.OrgLink}}/settings">
{{svg "octicon-gear" 14}} {{ctx.Locale.Tr "org.settings.pinned.manage"}}
</a>
{{end}}
</h4>
{{if .HasPinnedRepos}}
{{/* Ungrouped pinned repos */}}
{{if .UngroupedPinned}}
<div class="ui three stackable cards pinned-repos">
{{range .UngroupedPinned}}
{{if .Repo}}
<a class="ui card" href="{{.Repo.Link}}">
<div class="content">
<div class="header text truncate">
{{if .Repo.IsPrivate}}{{svg "octicon-lock" 16}}{{else if .Repo.IsFork}}{{svg "octicon-repo-forked" 16}}{{else if .Repo.IsMirror}}{{svg "octicon-mirror" 16}}{{else}}{{svg "octicon-repo" 16}}{{end}}
{{.Repo.Name}}
</div>
{{if .Repo.Description}}
<div class="description text truncate">{{.Repo.Description}}</div>
{{end}}
</div>
<div class="extra content">
{{if .Repo.PrimaryLanguage}}
<span class="tw-mr-2">
<span class="repo-language-color" style="background-color: {{.Repo.PrimaryLanguage.Color}}"></span>
{{.Repo.PrimaryLanguage.Language}}
</span>
{{end}}
{{if .Repo.NumStars}}
<span class="tw-mr-2">{{svg "octicon-star" 14}} {{.Repo.NumStars}}</span>
{{end}}
{{if .Repo.NumForks}}
<span>{{svg "octicon-repo-forked" 14}} {{.Repo.NumForks}}</span>
{{end}}
</div>
</a>
{{end}}
{{end}}
</div>
{{end}}
{{/* Grouped pinned repos */}}
{{range .PinnedGroups}}
{{$groupRepos := index $.PinnedByGroup .ID}}
{{if $groupRepos}}
<div class="pinned-group tw-mt-4">
<h5 class="ui header tw-mb-2">
{{svg "octicon-chevron-down" 14}} {{.Name}}
</h5>
<div class="ui three stackable cards pinned-repos">
{{range $groupRepos}}
{{if .Repo}}
<a class="ui card" href="{{.Repo.Link}}">
<div class="content">
<div class="header text truncate">
{{if .Repo.IsPrivate}}{{svg "octicon-lock" 16}}{{else if .Repo.IsFork}}{{svg "octicon-repo-forked" 16}}{{else if .Repo.IsMirror}}{{svg "octicon-mirror" 16}}{{else}}{{svg "octicon-repo" 16}}{{end}}
{{.Repo.Name}}
</div>
{{if .Repo.Description}}
<div class="description text truncate">{{.Repo.Description}}</div>
{{end}}
</div>
<div class="extra content">
{{if .Repo.PrimaryLanguage}}
<span class="tw-mr-2">
<span class="repo-language-color" style="background-color: {{.Repo.PrimaryLanguage.Color}}"></span>
{{.Repo.PrimaryLanguage.Language}}
</span>
{{end}}
{{if .Repo.NumStars}}
<span class="tw-mr-2">{{svg "octicon-star" 14}} {{.Repo.NumStars}}</span>
{{end}}
{{if .Repo.NumForks}}
<span>{{svg "octicon-repo-forked" 14}} {{.Repo.NumForks}}</span>
{{end}}
</div>
</a>
{{end}}
{{end}}
</div>
</div>
{{end}}
{{end}}
{{else}}
{{/* Empty state for pinned repos */}}
<div class="ui placeholder segment tw-text-center">
<div class="ui icon header">
{{svg "octicon-pin" 48}}
<div class="content">
{{ctx.Locale.Tr "org.pinned_repos_empty_title"}}
<div class="sub header">
{{ctx.Locale.Tr "org.pinned_repos_empty_desc"}}
</div>
</div>
</div>
{{if .IsOrganizationOwner}}
<div class="tw-mt-4">
<a class="ui primary button" href="{{.OrgLink}}/settings">
{{svg "octicon-gear" 16}} {{ctx.Locale.Tr "org.settings.pinned.setup"}}
</a>
</div>
{{end}}
</div>
{{end}}
</div>
{{/* Public Members Section */}}
<div class="ui segment public-members-section tw-mt-4">
<h4 class="ui header tw-flex tw-items-center">
{{svg "octicon-people" 16}} {{ctx.Locale.Tr "org.public_members"}}
{{if .HasMorePublicMembers}}
<a class="tw-ml-auto text grey tw-text-sm" href="{{.OrgLink}}/members">{{ctx.Locale.Tr "org.view_all_members" .TotalPublicMembers}}</a>
{{end}}
</h4>
{{if .PublicMembers}}
<div class="tw-flex tw-flex-wrap tw-gap-4">
{{range .PublicMembers}}
<a href="{{.User.HomeLink}}" title="{{.User.Name}}{{if .User.FullName}} ({{.User.FullName}}){{end}}" class="tw-flex tw-flex-col tw-items-center tw-p-2 tw-no-underline">
{{ctx.AvatarUtils.Avatar .User 48}}
<span class="tw-text-sm tw-mt-1 text primary">{{.User.Name}}</span>
{{if .Role}}<span class="tw-text-xs text grey">{{.Role}}</span>{{end}}
</a>
{{end}}
</div>
{{else}}
<div class="ui placeholder segment tw-text-center">
<div class="ui icon header">
{{svg "octicon-person" 32}}
<div class="sub header">
{{ctx.Locale.Tr "org.no_public_members"}}
</div>
</div>
</div>
{{end}}
</div>
{{/* Organization Stats */}}
{{if .OrgStats}}
<div class="ui segment org-stats-section tw-mt-4">
<h4 class="ui header">
{{svg "octicon-graph" 16}} {{ctx.Locale.Tr "org.activity"}}
</h4>
<div class="ui four mini statistics">
<div class="statistic">
<div class="value">{{.OrgStats.TotalRepos}}</div>
<div class="label">{{ctx.Locale.Tr "org.repositories"}}</div>
</div>
<div class="statistic">
<div class="value">{{.OrgStats.TotalMembers}}</div>
<div class="label">{{ctx.Locale.Tr "org.members"}}</div>
</div>
<div class="statistic">
<div class="value">{{.OrgStats.TotalTeams}}</div>
<div class="label">{{ctx.Locale.Tr "org.teams"}}</div>
</div>
<div class="statistic">
<div class="value">{{.OrgStats.TotalStars}}</div>
<div class="label">{{ctx.Locale.Tr "repo.stars"}}</div>
</div>
</div>
</div>
{{end}}
{{end}}
</div>
{{end}}
{{/* Public Members Section (on overview) */}}
{{if and .PageIsViewOverview .PublicMembers}}
<div class="ui segment public-members-section tw-mt-4">
<h4 class="ui header tw-flex tw-items-center">
{{svg "octicon-people" 16}} {{ctx.Locale.Tr "org.public_members"}}
{{if .HasMorePublicMembers}}
<a class="tw-ml-auto text grey tw-text-sm" href="{{.OrgLink}}/members">{{ctx.Locale.Tr "org.view_all_members" .TotalPublicMembers}}</a>
{{end}}
</h4>
<div class="tw-flex tw-flex-wrap tw-gap-2">
{{range .PublicMembers}}
<a href="{{.User.HomeLink}}" title="{{.User.Name}} ({{.Role}})" class="tw-flex tw-flex-col tw-items-center tw-p-2">
{{ctx.AvatarUtils.Avatar .User 48}}
<span class="tw-text-sm tw-mt-1">{{.User.Name}}</span>
<span class="tw-text-xs text grey">{{.Role}}</span>
</a>
{{end}}
{{/* Profile README Empty State */}}
{{if and (not .ProfileReadmeContent) .IsOrganizationOwner}}
<div class="ui segment tw-mt-4">
<div class="ui placeholder segment tw-text-center">
<div class="ui icon header">
{{svg "octicon-book" 32}}
<div class="content">
{{ctx.Locale.Tr "org.profile_readme_empty_title"}}
<div class="sub header">
{{ctx.Locale.Tr "org.profile_readme_empty_desc"}}
</div>
</div>
</div>
<div class="tw-mt-4">
<a class="ui primary button" href="{{AppSubUrl}}/repo/create?org={{.Org.ID}}&name=.profile">
{{svg "octicon-plus" 16}} {{ctx.Locale.Tr "org.create_profile_repo"}}
</a>
</div>
</div>
</div>
</div>
{{end}}
{{end}}
{{/* Repositories Tab Content */}}
{{if .PageIsViewRepositories}}
{{template "shared/repo/search" .}}
{{template "shared/repo/list" .}}

View File

@@ -1,12 +1,10 @@
<div class="ui container">
<overflow-menu class="ui secondary pointing tabular borderless menu tw-mb-4">
<div class="overflow-menu-items">
{{if .HasOrgProfileReadme}}
<a class="{{if .PageIsViewOverview}}active {{end}}item" href="{{$.Org.HomeLink}}">
{{svg "octicon-info"}} {{ctx.Locale.Tr "user.overview"}}
</a>
{{end}}
<a class="{{if .PageIsViewRepositories}}active {{end}}item" href="{{$.Org.HomeLink}}{{if .HasOrgProfileReadme}}/-/repositories{{end}}">
<a class="{{if .PageIsViewOverview}}active {{end}}item" href="{{$.Org.HomeLink}}">
{{svg "octicon-info"}} {{ctx.Locale.Tr "user.overview"}}
</a>
<a class="{{if .PageIsViewRepositories}}active {{end}}item" href="{{$.Org.HomeLink}}/-/repositories">
{{svg "octicon-repo"}} {{ctx.Locale.Tr "user.repositories"}}
{{if .RepoCount}}
<div class="ui small label">{{.RepoCount}}</div>