diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index afcf9ade04da7..607a340b21d38 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2358,9 +2358,9 @@ tag.create_tag_from = Create new tag from '%s' tag.create_success = Tag '%s' has been created. topic.manage_topics = Manage Topics -topic.done = Done topic.count_prompt = You cannot select more than 25 topics topic.format_prompt = Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long. +topic.remove_topic = Remove topic "%s" find_file.go_to_file = Go to file find_file.no_matching = No matching file found diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 73afbd663db39..d07980de14b66 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -28,34 +28,33 @@ {{end}} -
- {{range .Topics}}{{.Name}}{{end}} - {{if and .Permission.IsAdmin (not .Repository.IsArchived)}}{{.locale.Tr "repo.topic.manage_topics"}}{{end}} +
+ {{range .Topics}}{{.Name}}{{end}} + {{if and .Permission.IsAdmin (not .Repository.IsArchived)}}{{end}}
{{end}} {{if and .Permission.IsAdmin (not .Repository.IsArchived)}} -
-
-
- +
+
+
-
- {{.locale.Tr "repo.topic.done"}} +
+ +
{{end}} -
- {{.locale.Tr "repo.topic.count_prompt"}} - {{.locale.Tr "repo.topic.format_prompt"}} -
{{if .Repository.IsArchived}}
{{.locale.Tr "repo.archive.title"}} diff --git a/web_src/css/base.css b/web_src/css/base.css index 225359b765ce2..1f62da5351f78 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -2382,6 +2382,10 @@ a.ui.label:hover { color: var(--color-text); } +.ui.tertiary.button:focus { + color: var(--color-text-dark); +} + .ui.primary.label, .ui.primary.labels .label { background-color: var(--color-primary) !important; diff --git a/web_src/css/helpers.css b/web_src/css/helpers.css index 9e974b9ea1b0e..51115384fa34b 100644 --- a/web_src/css/helpers.css +++ b/web_src/css/helpers.css @@ -22,6 +22,7 @@ /* below class names match Tailwind CSS */ .gt-pointer-events-none { pointer-events: none !important; } .gt-relative { position: relative !important; } +.gt-cursor-default { cursor: default !important; } .gt-mono { font-family: var(--fonts-monospace) !important; diff --git a/web_src/css/repository.css b/web_src/css/repository.css index ad2ac49b9984a..7ed7195a3a3fe 100644 --- a/web_src/css/repository.css +++ b/web_src/css/repository.css @@ -3049,21 +3049,10 @@ tbody.commit-list { top: -2px; } -#topic_edit { - margin-top: 5px; -} - -#repo-topics { - margin-top: 5px; - display: flex; - align-items: center; - flex-wrap: wrap; -} - -.repo-topic { - font-weight: normal !important; +#repo-topics .repo-topic { + font-weight: normal; cursor: pointer; - margin: 2px !important; + margin: 2px; } #new-dependency-drop-list.ui.selection.dropdown { @@ -3079,18 +3068,6 @@ tbody.commit-list { overflow: hidden; } -#manage_topic { - font-size: 12px; -} - -.label + #manage_topic { - margin-left: 5px; -} - -.ui.small.label.topic { - margin-bottom: 4px; -} - .repo-header { display: flex; align-items: center; diff --git a/web_src/js/features/repo-home.js b/web_src/js/features/repo-home.js index dfccffc79488a..628d310294d21 100644 --- a/web_src/js/features/repo-home.js +++ b/web_src/js/features/repo-home.js @@ -1,32 +1,47 @@ import $ from 'jquery'; import {stripTags} from '../utils.js'; import {hideElem, showElem} from '../utils/dom.js'; +import {htmlEscape} from 'escape-goat'; +import {svg} from '../svg.js'; const {appSubUrl, csrfToken} = window.config; export function initRepoTopicBar() { const mgrBtn = $('#manage_topic'); - const editDiv = $('#topic_edit'); - const viewDiv = $('#repo-topics'); + if (!mgrBtn.length) return; + const saveBtn = $('#save_topic'); + const topicListDiv = $('#repo-topics'); const topicDropdown = $('#topic_edit .dropdown'); - const topicForm = $('#topic_edit.ui.form'); - const topicPrompts = getPrompts(); + const topicDropdownSearch = topicDropdown.find('input.search'); + const topicForm = $('#topic_edit'); + const topicPrompts = { + countPrompt: topicDropdown.attr('data-text-count-prompt'), + formatPrompt: topicDropdown.attr('data-text-format-prompt'), + removeTopic: topicDropdown.attr('data-text-remove-topic'), + }; + + function addLabelDeleteIconAria($el) { + $el.removeAttr('aria-hidden').each(function() { + $(this).attr({ + 'aria-label': topicPrompts.removeTopic.replace('%s', $(this).parent().attr('data-value')), + 'role': 'button', + }); + }); + } mgrBtn.on('click', () => { - hideElem(viewDiv); - showElem(editDiv); + hideElem(topicListDiv); + showElem(topicForm); + addLabelDeleteIconAria(topicDropdown.find('.delete.icon')); + topicDropdownSearch.focus(); }); - function getPrompts() { - const hidePrompt = $('#validate_prompt'); - const prompts = { - countPrompt: hidePrompt.children('#count_prompt').text(), - formatPrompt: hidePrompt.children('#format_prompt').text() - }; - hidePrompt.remove(); - return prompts; - } + $('#cancel_topic_edit').on('click', () => { + hideElem(topicForm); + showElem(topicListDiv); + mgrBtn.focus(); + }); saveBtn.on('click', () => { const topics = $('input[name=topics]').val(); @@ -36,20 +51,18 @@ export function initRepoTopicBar() { topics }, (_data, _textStatus, xhr) => { if (xhr.responseJSON.status === 'ok') { - viewDiv.children('.topic').remove(); + topicListDiv.children('.topic').remove(); if (topics.length) { const topicArray = topics.split(','); - - const last = viewDiv.children('a').last(); for (let i = 0; i < topicArray.length; i++) { const link = $(''); link.attr('href', `${appSubUrl}/explore/repos?q=${encodeURIComponent(topicArray[i])}&topic=1`); link.text(topicArray[i]); - link.insertBefore(last); + link.insertBefore(mgrBtn); // insert all new topics before manage button } } - hideElem(editDiv); - showElem(viewDiv); + hideElem(topicForm); + showElem(topicListDiv); } }).fail((xhr) => { if (xhr.status === 422) { @@ -101,7 +114,7 @@ export function initRepoTopicBar() { const query = stripTags(this.urlData.query.trim()); let found_query = false; const current_topics = []; - topicDropdown.find('div.label.visible.topic,a.label.visible').each((_, el) => { + topicDropdown.find('div.label.visible.topic').each((_, el) => { current_topics.push(el.getAttribute('data-value')); }); @@ -140,8 +153,11 @@ export function initRepoTopicBar() { }, onLabelCreate(value) { value = value.toLowerCase().trim(); - this.attr('data-value', value).contents().first().replaceWith(value); - return $(this); + // `this` is the default label (jQuery object), it's a `$('')` + // we create a new div element to replace it, to keep the same as template (repo-topic-label), because we do not want the `` tag which affects aria focus. + const $el = $(`
${htmlEscape(value)}${svg('octicon-x', 16, 'delete icon gt-ml-3 gt-mt-1')}
`); + addLabelDeleteIconAria($el.find('.delete.icon')); + return $el; }, onAdd(addedValue, _addedText, $addedChoice) { addedValue = addedValue.toLowerCase().trim();