From 6ee3a8a039ed492d44e80b6f14f222a96763b196 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Tue, 30 Apr 2024 16:40:09 +0800 Subject: [PATCH 1/7] Right align the "Settings" menu item in overflow-menu (#30764) (#30777) Backport #30764 by wxiaoguang Co-authored-by: wxiaoguang --- templates/org/menu.tmpl | 3 ++- templates/repo/header.tmpl | 1 + web_src/css/base.css | 17 ++++++++++++ web_src/css/modules/container.css | 32 ----------------------- web_src/js/webcomponents/overflow-menu.js | 24 +++++++++++++---- 5 files changed, 39 insertions(+), 38 deletions(-) diff --git a/templates/org/menu.tmpl b/templates/org/menu.tmpl index c519606d1f..698a9559c5 100644 --- a/templates/org/menu.tmpl +++ b/templates/org/menu.tmpl @@ -40,8 +40,9 @@ {{end}} {{if .IsOrganizationOwner}} + - {{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}} + {{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}} {{end}} diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index 775aa30063..c0d833a187 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -216,6 +216,7 @@ {{template "custom/extra_tabs" .}} {{if .Permission.IsAdmin}} + {{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}} diff --git a/web_src/css/base.css b/web_src/css/base.css index 58a5723cb5..bca581eae6 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -942,6 +942,23 @@ overflow-menu .overflow-menu-items .item { margin-bottom: 0 !important; /* reset fomantic's margin, because the active menu has special bottom border */ } +overflow-menu .overflow-menu-items .item-flex-space { + flex: 1; +} + +overflow-menu .overflow-menu-button { + background: transparent; + border: none; + color: inherit; + text-align: center; + width: 32px; + padding: 0; +} + +overflow-menu .overflow-menu-button:hover { + color: var(--color-text-dark); +} + overflow-menu .ui.label { margin-left: 7px !important; /* save some space */ } diff --git a/web_src/css/modules/container.css b/web_src/css/modules/container.css index f394d6c06d..9f67ceb8d5 100644 --- a/web_src/css/modules/container.css +++ b/web_src/css/modules/container.css @@ -6,38 +6,6 @@ max-width: 100%; } -@media (max-width: 767.98px) { - .ui.ui.ui.container:not(.fluid) { - width: auto; - margin-left: 1em; - margin-right: 1em; - } -} - -@media (min-width: 768px) and (max-width: 991.98px) { - .ui.ui.ui.container:not(.fluid) { - width: 723px; - margin-left: auto; - margin-right: auto; - } -} - -@media (min-width: 992px) and (max-width: 1199.98px) { - .ui.ui.ui.container:not(.fluid) { - width: 933px; - margin-left: auto; - margin-right: auto; - } -} - -@media (min-width: 1200px) { - .ui.ui.ui.container:not(.fluid) { - width: 1127px; - margin-left: auto; - margin-right: auto; - } -} - .ui.fluid.container { width: 100%; } diff --git a/web_src/js/webcomponents/overflow-menu.js b/web_src/js/webcomponents/overflow-menu.js index 604fce7d4b..0778c5990f 100644 --- a/web_src/js/webcomponents/overflow-menu.js +++ b/web_src/js/webcomponents/overflow-menu.js @@ -8,7 +8,7 @@ window.customElements.define('overflow-menu', class extends HTMLElement { if (!this.tippyContent) { const div = document.createElement('div'); div.classList.add('tippy-target'); - div.tabIndex = '-1'; // for initial focus, programmatic focus only + div.tabIndex = -1; // for initial focus, programmatic focus only div.addEventListener('keydown', (e) => { if (e.key === 'Tab') { const items = this.tippyContent.querySelectorAll('[role="menuitem"]'); @@ -60,21 +60,35 @@ window.customElements.define('overflow-menu', class extends HTMLElement { this.tippyContent = div; } + const itemFlexSpace = this.menuItemsEl.querySelector('.item-flex-space'); + // move items in tippy back into the menu items for subsequent measurement for (const item of this.tippyItems || []) { - this.menuItemsEl.append(item); + if (!itemFlexSpace || item.getAttribute('data-after-flex-space')) { + this.menuItemsEl.append(item); + } else { + itemFlexSpace.insertAdjacentElement('beforebegin', item); + } } // measure which items are partially outside the element and move them into the button menu + itemFlexSpace?.style.setProperty('display', 'none', 'important'); this.tippyItems = []; const menuRight = this.offsetLeft + this.offsetWidth; - const menuItems = this.menuItemsEl.querySelectorAll('.item'); + const menuItems = this.menuItemsEl.querySelectorAll('.item, .item-flex-space'); + let afterFlexSpace = false; for (const item of menuItems) { + if (item.classList.contains('item-flex-space')) { + afterFlexSpace = true; + continue; + } + if (afterFlexSpace) item.setAttribute('data-after-flex-space', 'true'); const itemRight = item.offsetLeft + item.offsetWidth; - if (menuRight - itemRight < 38) { // roughly the width of .overflow-menu-button + if (menuRight - itemRight < 38) { // roughly the width of .overflow-menu-button with some extra space this.tippyItems.push(item); } } + itemFlexSpace?.style.removeProperty('display'); // if there are no overflown items, remove any previously created button if (!this.tippyItems?.length) { @@ -105,7 +119,7 @@ window.customElements.define('overflow-menu', class extends HTMLElement { // create button initially const btn = document.createElement('button'); - btn.classList.add('overflow-menu-button', 'btn', 'tw-px-2', 'hover:tw-text-text-dark'); + btn.classList.add('overflow-menu-button'); btn.setAttribute('aria-label', window.config.i18n.more_items); btn.innerHTML = octiconKebabHorizontal; this.append(btn); From dc9e795ce221f0301c0f7e3c16685396f4e446e6 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Tue, 30 Apr 2024 17:40:47 +0800 Subject: [PATCH 2/7] Fix issue label rendering in the issue popup (#30763) (#30773) Backport #30763 by wxiaoguang Co-authored-by: wxiaoguang --- modules/templates/util_render.go | 39 +++++++++++------------- routers/web/repo/issue.go | 5 ++- tests/integration/issue_test.go | 11 +++++-- web_src/js/components/ContextPopup.vue | 27 ++++------------ web_src/js/features/common-issue-list.js | 2 +- 5 files changed, 36 insertions(+), 48 deletions(-) diff --git a/modules/templates/util_render.go b/modules/templates/util_render.go index 659422aee7..b15de6521d 100644 --- a/modules/templates/util_render.go +++ b/modules/templates/util_render.go @@ -121,29 +121,25 @@ func RenderIssueTitle(ctx context.Context, text string, metas map[string]string) // RenderLabel renders a label // locale is needed due to an import cycle with our context providing the `Tr` function func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_model.Label) template.HTML { - var ( - archivedCSSClass string - textColor = util.ContrastColor(label.Color) - labelScope = label.ExclusiveScope() - ) - - description := emoji.ReplaceAliases(template.HTMLEscapeString(label.Description)) + var extraCSSClasses string + textColor := util.ContrastColor(label.Color) + labelScope := label.ExclusiveScope() + descriptionText := emoji.ReplaceAliases(label.Description) if label.IsArchived() { - archivedCSSClass = "archived-label" - description = fmt.Sprintf("(%s) %s", locale.TrString("archived"), description) + extraCSSClasses = "archived-label" + descriptionText = fmt.Sprintf("(%s) %s", locale.TrString("archived"), descriptionText) } if labelScope == "" { // Regular label - s := fmt.Sprintf("
%s
", - archivedCSSClass, textColor, label.Color, description, RenderEmoji(ctx, label.Name)) - return template.HTML(s) + return HTMLFormat(`
%s
`, + extraCSSClasses, textColor, label.Color, descriptionText, RenderEmoji(ctx, label.Name)) } // Scoped label - scopeText := RenderEmoji(ctx, labelScope) - itemText := RenderEmoji(ctx, label.Name[len(labelScope)+1:]) + scopeHTML := RenderEmoji(ctx, labelScope) + itemHTML := RenderEmoji(ctx, label.Name[len(labelScope)+1:]) // Make scope and item background colors slightly darker and lighter respectively. // More contrast needed with higher luminance, empirically tweaked. @@ -171,14 +167,13 @@ func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_m itemColor := "#" + hex.EncodeToString(itemBytes) scopeColor := "#" + hex.EncodeToString(scopeBytes) - s := fmt.Sprintf(""+ - "
%s
"+ - "
%s
"+ - "
", - archivedCSSClass, description, - textColor, scopeColor, scopeText, - textColor, itemColor, itemText) - return template.HTML(s) + return HTMLFormat(``+ + `
%s
`+ + `
%s
`+ + `
`, + extraCSSClasses, descriptionText, + textColor, scopeColor, scopeHTML, + textColor, itemColor, itemHTML) } // RenderEmoji renders html text with emoji post processors diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index de6ef9e93b..0c8363a168 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -2177,7 +2177,10 @@ func GetIssueInfo(ctx *context.Context) { } } - ctx.JSON(http.StatusOK, convert.ToIssue(ctx, ctx.Doer, issue)) + ctx.JSON(http.StatusOK, map[string]any{ + "convertedIssue": convert.ToIssue(ctx, ctx.Doer, issue), + "renderedLabels": templates.RenderLabels(ctx, ctx.Locale, issue.Labels, ctx.Repo.RepoLink, issue), + }) } // UpdateIssueTitle change issue's title diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go index 44d362d9c7..b7952b0879 100644 --- a/tests/integration/issue_test.go +++ b/tests/integration/issue_test.go @@ -6,6 +6,7 @@ package integration import ( "context" "fmt" + "html/template" "net/http" "net/url" "path" @@ -573,10 +574,14 @@ func TestGetIssueInfo(t *testing.T) { urlStr := fmt.Sprintf("/%s/%s/issues/%d/info", owner.Name, repo.Name, issue.Index) req := NewRequest(t, "GET", urlStr) resp := session.MakeRequest(t, req, http.StatusOK) - var apiIssue api.Issue - DecodeJSON(t, resp, &apiIssue) + var respStruct struct { + ConvertedIssue api.Issue + RenderedLabels template.HTML + } + DecodeJSON(t, resp, &respStruct) - assert.EqualValues(t, issue.ID, apiIssue.ID) + assert.EqualValues(t, issue.ID, respStruct.ConvertedIssue.ID) + assert.Contains(t, string(respStruct.RenderedLabels), `"labels-list"`) } func TestUpdateIssueDeadline(t *testing.T) { diff --git a/web_src/js/components/ContextPopup.vue b/web_src/js/components/ContextPopup.vue index 65a6089522..e4e8bce184 100644 --- a/web_src/js/components/ContextPopup.vue +++ b/web_src/js/components/ContextPopup.vue @@ -1,6 +1,5 @@