mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-08-24 19:23:53 +00:00
feat(ui): improve org header with new noJS dropdown and more options (#8572)
Related: https://codeberg.org/forgejo/forgejo/pulls/6977/files#diff-fd05eba523810d46c7763db938ad5839372a074a, https://codeberg.org/forgejo/forgejo/pulls/3949, https://codeberg.org/forgejo/forgejo/pulls/7906 * use the new noJS dropdown for extra actions in org view (currently only includes report button) * this required some refactoring of the area because the said dropdown was not built to be placed in an area where `font-size:36px` is forced onto everything * this greatly improves consistently with user profiles which now use this type of dropdown * I decided against making the opener button mimicrate an actual button because it looks ok as is and is consitent with menu in user profiles and because I don't think this is a good design language to make a kebab menu opener look this way * add icon to the entry * add atom entry Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8572 Reviewed-by: Gusted <gusted@noreply.codeberg.org> Reviewed-by: Beowulf <beowulf@beocode.eu> Co-authored-by: 0ko <0ko@noreply.codeberg.org> Co-committed-by: 0ko <0ko@noreply.codeberg.org>
This commit is contained in:
parent
b06f4fdd63
commit
c11dd3fb46
5 changed files with 88 additions and 27 deletions
|
@ -1,4 +1,4 @@
|
||||||
<button class="ui basic button tw-mr-0" hx-post="{{.Org.HomeLink}}?action={{if $.IsFollowing}}unfollow{{else}}follow{{end}}">
|
<button class="ui basic button" hx-post="{{.Org.HomeLink}}?action={{if $.IsFollowing}}unfollow{{else}}follow{{end}}">
|
||||||
{{if $.IsFollowing}}
|
{{if $.IsFollowing}}
|
||||||
{{ctx.Locale.Tr "user.unfollow"}}
|
{{ctx.Locale.Tr "user.unfollow"}}
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
|
@ -1,33 +1,41 @@
|
||||||
<div class="ui container tw-flex">
|
<div class="ui container tw-flex tw-gap-x-4">
|
||||||
{{ctx.AvatarUtils.Avatar .Org 100 "org-avatar"}}
|
{{ctx.AvatarUtils.Avatar .Org 100 "org-avatar"}}
|
||||||
<div id="org-info" class="tw-flex tw-flex-col">
|
<div id="org-info" class="tw-flex tw-flex-col">
|
||||||
<div class="ui header">
|
<div class="org-header tw-flex">
|
||||||
<div class="org-title">
|
<div class="org-title">
|
||||||
{{.Org.DisplayName}}
|
<h1>{{.Org.DisplayName}}</h1>
|
||||||
<span class="org-visibility">
|
<span class="org-visibility">
|
||||||
{{if .Org.Visibility.IsLimited}}<span class="ui large horizontal label">{{ctx.Locale.Tr "org.settings.visibility.limited_shortname"}}</span>{{end}}
|
{{if .Org.Visibility.IsLimited}}<span class="ui large horizontal label">{{ctx.Locale.Tr "org.settings.visibility.limited_shortname"}}</span>{{end}}
|
||||||
{{if .Org.Visibility.IsPrivate}}<span class="ui large horizontal label">{{ctx.Locale.Tr "org.settings.visibility.private_shortname"}}</span>{{end}}
|
{{if .Org.Visibility.IsPrivate}}<span class="ui large horizontal label">{{ctx.Locale.Tr "org.settings.visibility.private_shortname"}}</span>{{end}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="tw-flex tw-items-center button-row tw-ml-auto tw-text-16 tw-whitespace-nowrap">
|
<span class="button-sequence tw-items-center tw-ml-auto tw-whitespace-nowrap">
|
||||||
{{if .EnableFeed}}
|
|
||||||
<a class="ui basic label button tw-mr-0" href="{{.Org.HomeLink}}.rss" data-tooltip-content="{{ctx.Locale.Tr "rss_feed"}}">
|
|
||||||
{{svg "octicon-rss" 24}}
|
|
||||||
</a>
|
|
||||||
{{end}}
|
|
||||||
{{if .IsSigned}}
|
{{if .IsSigned}}
|
||||||
{{template "org/follow_unfollow" .}}
|
{{template "org/follow_unfollow" .}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .IsOrganizationMember}}
|
{{if .IsOrganizationMember}}
|
||||||
<a class="ui basic button tw-mr-0" href="{{.OrgLink}}/dashboard">{{ctx.Locale.Tr "org.open_dashboard"}}</a>
|
<a class="ui basic button" href="{{.OrgLink}}/dashboard">{{ctx.Locale.Tr "org.open_dashboard"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if and .IsModerationEnabled .IsSigned (not .IsOrganizationOwner)}}
|
{{$moderationEntryNeeded := and .IsModerationEnabled .IsSigned (not .IsOrganizationOwner)}}
|
||||||
<button class="ui dropdown icon button" data-tooltip-content="{{ctx.Locale.Tr "repo.more_operations"}}" aria-label="{{ctx.Locale.Tr "toggle_menu"}}">
|
{{if or .EnableFeed $moderationEntryNeeded}}
|
||||||
{{svg "octicon-kebab-horizontal" 14}}
|
<details class="dropdown dir-rtl">
|
||||||
<div class="menu top left">
|
<summary data-tooltip-content="{{ctx.Locale.Tr "profile.actions.tooltip"}}">{{svg "octicon-kebab-horizontal" 20}}</summary>
|
||||||
<a class="item context" href="{{AppSubUrl}}/report_abuse?type=org&id={{$.Org.ID}}">{{ctx.Locale.Tr "moderation.report_abuse"}}</a>
|
<ul>
|
||||||
</div>
|
{{if .EnableFeed}}
|
||||||
</button>
|
<li>
|
||||||
|
<a class="item" href="{{.Org.HomeLink}}.rss">{{svg "octicon-rss"}}{{ctx.Locale.Tr "rss_feed"}}</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="item" href="{{.Org.HomeLink}}.atom">{{svg "octicon-rss"}}{{ctx.Locale.Tr "feed.atom.link"}}</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
{{if $moderationEntryNeeded}}
|
||||||
|
<li>
|
||||||
|
<a class="item orange text" href="{{AppSubUrl}}/report_abuse?type=org&id={{$.Org.ID}}">{{svg "octicon-stop"}}{{ctx.Locale.Tr "moderation.report_abuse"}}</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
{{end}}
|
{{end}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -104,5 +104,51 @@ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequa
|
||||||
assert.NotContains(t, resp.Body.String(), "veniam")
|
assert.NotContains(t, resp.Body.String(), "veniam")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("More actions - feeds only", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
defer test.MockVariableValue(&setting.Other.EnableFeed, true)()
|
||||||
|
defer test.MockVariableValue(&setting.Moderation.Enabled, false)()
|
||||||
|
|
||||||
|
// Both guests and logged in users should see the feed option
|
||||||
|
doc := NewHTMLParser(t, MakeRequest(t, NewRequest(t, "GET", "/org3"), http.StatusOK).Body)
|
||||||
|
doc.AssertElement(t, "details.dropdown a[href='/org3.rss']", true)
|
||||||
|
doc.AssertElement(t, "details.dropdown a[href^='/report_abuse']", false)
|
||||||
|
|
||||||
|
doc = NewHTMLParser(t, loginUser(t, "user10").MakeRequest(t, NewRequest(t, "GET", "/org3"), http.StatusOK).Body)
|
||||||
|
doc.AssertElement(t, "details.dropdown a[href='/org3.rss']", true)
|
||||||
|
doc.AssertElement(t, "details.dropdown a[href^='/report_abuse']", false)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("More actions - none", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
defer test.MockVariableValue(&setting.Other.EnableFeed, false)()
|
||||||
|
defer test.MockVariableValue(&setting.Moderation.Enabled, false)()
|
||||||
|
|
||||||
|
// The dropdown won't appear if no entries are available, for both guests and logged in users
|
||||||
|
doc := NewHTMLParser(t, MakeRequest(t, NewRequest(t, "GET", "/org3"), http.StatusOK).Body)
|
||||||
|
doc.AssertElement(t, "details.dropdown", false)
|
||||||
|
|
||||||
|
doc = NewHTMLParser(t, loginUser(t, "user10").MakeRequest(t, NewRequest(t, "GET", "/org3"), http.StatusOK).Body)
|
||||||
|
doc.AssertElement(t, "details.dropdown", false)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("More actions - moderation", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
defer test.MockVariableValue(&setting.Other.EnableFeed, false)()
|
||||||
|
defer test.MockVariableValue(&setting.Moderation.Enabled, true)()
|
||||||
|
|
||||||
|
// The report option shouldn't be available to a guest
|
||||||
|
doc := NewHTMLParser(t, MakeRequest(t, NewRequest(t, "GET", "/org3"), http.StatusOK).Body)
|
||||||
|
doc.AssertElement(t, "details.dropdown", false)
|
||||||
|
|
||||||
|
// But should be available to a logged in user
|
||||||
|
doc = NewHTMLParser(t, loginUser(t, "user10").MakeRequest(t, NewRequest(t, "GET", "/org3"), http.StatusOK).Body)
|
||||||
|
doc.AssertElement(t, "details.dropdown a[href^='/report_abuse']", true)
|
||||||
|
|
||||||
|
// But the org owner shouldn't see the report option
|
||||||
|
doc = NewHTMLParser(t, loginUser(t, "user1").MakeRequest(t, NewRequest(t, "GET", "/org3"), http.StatusOK).Body)
|
||||||
|
doc.AssertElement(t, "details.dropdown", false)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,13 @@ details.dropdown > summary + ul > li:last-child {
|
||||||
/* Note: https://css-tricks.com/css-anchor-positioning-guide/
|
/* Note: https://css-tricks.com/css-anchor-positioning-guide/
|
||||||
* looks like a great thing but FF still doesn't support it. */
|
* looks like a great thing but FF still doesn't support it. */
|
||||||
|
|
||||||
/* Note: dropdown.dir-rtl can be implemented when needed, e.g. for navbar profile dropdown on desktop layout. */
|
details.dropdown.dir-rtl > summary + ul {
|
||||||
|
inset-inline: 0 auto;
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
details.dropdown.dir-rtl > summary + ul > li {
|
||||||
|
direction: ltr;
|
||||||
|
}
|
||||||
|
|
||||||
details.dropdown > summary + ul > li > .item {
|
details.dropdown > summary + ul > li > .item {
|
||||||
padding: var(--dropdown-item-padding);
|
padding: var(--dropdown-item-padding);
|
||||||
|
|
|
@ -89,28 +89,29 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-content.organization .org-avatar {
|
|
||||||
margin-right: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-content.organization #org-info {
|
.page-content.organization #org-info {
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-content.organization #org-info .ui.header {
|
.page-content.organization #org-info .org-title {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
column-gap: 1rem;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 36px;
|
}
|
||||||
margin-bottom: 0;
|
|
||||||
|
.page-content.organization #org-info .org-title h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 2.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767.98px) {
|
@media (max-width: 767.98px) {
|
||||||
.page-content.organization #org-info .ui.header {
|
.page-content.organization #org-info .org-header {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
.page-content.organization #org-info .org-title {
|
.page-content.organization #org-info .org-title {
|
||||||
|
flex-wrap: wrap;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue