mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Fine tune more downdrop settings, use SVG for labels, improve Repo Topic Edit form (#23626)
Although it seems that some different purposes are mixed in this PR, however, they are all related, and can be tested together, so I put them together to save everyone's time. Diff: `+79 −84`, everything becomes much better. ### Improve the dropdown settings. Move all fomantic-init related code into our `fomantic.js` Fine-tune some dropdown global settings, see the comments. Also help to fix the first problem in #23625 , cc: @yp05327 The "language" menu has been simplified, and it works with small-height window better. ### Use SVG instead of `<i class="delete icon">` It's also done by `$.fn.dropdown.settings.templates.label` , cc: @silverwind ### Remove incorrect `tabable` CSS class It doesn't have CSS styles, and it was only in Vue. So it's totally unnecessary, remove it by the way. ### Improve the Repo Topic Edit form * Simplify the code * Add a "Cancel" button * Align elements Before: <details>  </details> After: 
This commit is contained in:
		| @@ -19,9 +19,8 @@ | ||||
| 			{{if .ShowFooterBranding}} | ||||
| 				<a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea">{{svg "octicon-mark-github"}}<span class="sr-only">GitHub</span></a> | ||||
| 			{{end}} | ||||
| 			<div class="ui language bottom floating slide up dropdown link item"> | ||||
| 				{{svg "octicon-globe"}} | ||||
| 				<span>{{.locale.LangName}}</span> | ||||
| 			<div class="ui dropdown upward language"> | ||||
| 				<span>{{svg "octicon-globe"}} {{.locale.LangName}}</span> | ||||
| 				<div class="menu language-menu"> | ||||
| 					{{range .AllLangs}} | ||||
| 						<a lang="{{.Lang}}" data-url="{{AppSubUrl}}/?lang={{.Lang}}" class="item {{if eq $.locale.Lang .Lang}}active selected{{end}}">{{.Name}}</a> | ||||
|   | ||||
| @@ -28,34 +28,29 @@ | ||||
| 				</div> | ||||
| 			{{end}} | ||||
| 		</div> | ||||
| 		<div class="gt-mt-3" id="repo-topics"> | ||||
| 		<div class="gt-df gt-ac gt-fw gt-mt-3" id="repo-topics"> | ||||
| 			{{range .Topics}}<a class="ui repo-topic large label topic" href="{{AppSubUrl}}/explore/repos?q={{.Name}}&topic=1">{{.Name}}</a>{{end}} | ||||
| 		{{if and .Permission.IsAdmin (not .Repository.IsArchived)}}<a id="manage_topic" class="muted">{{.locale.Tr "repo.topic.manage_topics"}}</a>{{end}} | ||||
| 			{{if and .Permission.IsAdmin (not .Repository.IsArchived)}}<button id="manage_topic" class="ui button tiny tertiary gt-ml-2">{{.locale.Tr "repo.topic.manage_topics"}}</button>{{end}} | ||||
| 		</div> | ||||
| 		{{end}} | ||||
| 		{{if and .Permission.IsAdmin (not .Repository.IsArchived)}} | ||||
| 		<div class="ui repo-topic-edit grid form gt-hidden" id="topic_edit"> | ||||
| 			<div class="fourteen wide column"> | ||||
| 				<div class="field"> | ||||
| 					<div class="ui fluid multiple search selection dropdown"> | ||||
| 		<div class="ui form gt-hidden gt-df gt-mt-4" id="topic_edit"> | ||||
| 			<div class="field gt-f1 gt-mr-3"> | ||||
| 				<div class="ui fluid multiple search selection dropdown" data-text-count-prompt="{{.locale.Tr "repo.topic.count_prompt"}}" data-text-format-prompt="{{.locale.Tr "repo.topic.format_prompt"}}"> | ||||
| 					<input type="hidden" name="topics" value="{{range $i, $v := .Topics}}{{.Name}}{{if lt (Add $i 1) (len $.Topics)}},{{end}}{{end}}"> | ||||
| 					{{range .Topics}} | ||||
| 						<div class="ui small label topic transition visible" data-value="{{.Name}}" style="display: inline-block !important; cursor: default;">{{.Name}}{{svg "octicon-x" 16 "delete icon gt-ml-3 gt-mt-1"}}</div> | ||||
| 						{{/* keey the same layout as Fomantic UI generated labels */}} | ||||
| 						<a class="ui label transition visible gt-cursor-default" data-value="{{.Name}}" style="display: inline-block !important;">{{.Name}}{{svg "octicon-x" 16 "delete icon"}}</a> | ||||
| 					{{end}} | ||||
| 					<div class="text"></div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 			</div> | ||||
| 			<div class="two wide column"> | ||||
| 				<a class="ui button primary" role="button" tabindex="0" id="save_topic" | ||||
| 				data-link="{{.RepoLink}}/topics">{{.locale.Tr "repo.topic.done"}}</a> | ||||
| 			<div> | ||||
| 				<button class="ui basic button secondary" id="cancel_topic_edit">{{.locale.Tr "cancel"}}</button> | ||||
| 				<button class="ui primary button" id="save_topic" data-link="{{.RepoLink}}/topics">{{.locale.Tr "save"}}</button> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		{{end}} | ||||
| 		<div class="gt-hidden" id="validate_prompt"> | ||||
| 			<span id="count_prompt">{{.locale.Tr "repo.topic.count_prompt"}}</span> | ||||
| 			<span id="format_prompt">{{.locale.Tr "repo.topic.format_prompt"}}</span> | ||||
| 		</div> | ||||
| 		{{if .Repository.IsArchived}} | ||||
| 			<div class="ui warning message"> | ||||
| 				{{.locale.Tr "repo.archive.title"}} | ||||
|   | ||||
| @@ -1854,15 +1854,15 @@ footer .container .links > *:first-child { | ||||
| } | ||||
|  | ||||
| footer .ui.language .menu { | ||||
|   max-height: 500px; | ||||
|   height: 500px; | ||||
|   max-height: calc(100vh - 60px); | ||||
|   overflow-y: auto; | ||||
|   margin-bottom: 7px; | ||||
| } | ||||
|  | ||||
| footer .ui.language .svg { | ||||
|   margin-right: 0.15em; | ||||
|   vertical-align: top; | ||||
|   margin-top: calc(2em - 16px); | ||||
|   margin-top: 1px; | ||||
| } | ||||
|  | ||||
| footer .ui.left, | ||||
| @@ -2387,6 +2387,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; | ||||
|   | ||||
| @@ -23,6 +23,7 @@ | ||||
| .gt-pointer-events-none { pointer-events: none !important; } | ||||
| .gt-relative { position: relative !important; } | ||||
| .gt-overflow-x-scroll { overflow-x: scroll !important; } | ||||
| .gt-cursor-default { cursor: default !important; } | ||||
|  | ||||
| .gt-mono { | ||||
|   font-family: var(--fonts-monospace) !important; | ||||
|   | ||||
| @@ -3062,21 +3062,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 { | ||||
| @@ -3092,18 +3081,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; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <div v-if="!isOrganization" class="ui two item tabable menu"> | ||||
|     <div v-if="!isOrganization" class="ui two item menu"> | ||||
|       <a :class="{item: true, active: tab === 'repos'}" @click="changeTab('repos')">{{ textRepository }}</a> | ||||
|       <a :class="{item: true, active: tab === 'organizations'}" @click="changeTab('organizations')">{{ textOrganization }}</a> | ||||
|     </div> | ||||
|   | ||||
| @@ -83,7 +83,7 @@ export function initGlobalCommon() { | ||||
|   const $uiDropdowns = $('.ui.dropdown'); | ||||
|  | ||||
|   // do not init "custom" dropdowns, "custom" dropdowns are managed by their own code. | ||||
|   $uiDropdowns.filter(':not(.custom)').dropdown({fullTextSearch: 'exact'}); | ||||
|   $uiDropdowns.filter(':not(.custom)').dropdown(); | ||||
|  | ||||
|   // The "jump" means this dropdown is mainly used for "menu" purpose, | ||||
|   // clicking an item will jump to somewhere else or trigger an action/function. | ||||
| @@ -111,14 +111,12 @@ export function initGlobalCommon() { | ||||
|     }, | ||||
|   }); | ||||
|  | ||||
|   // special animations/popup-directions | ||||
|   $uiDropdowns.filter('.slide.up').dropdown({transition: 'slide up'}); | ||||
|   $uiDropdowns.filter('.upward').dropdown({direction: 'upward'}); | ||||
|   // special popup-directions | ||||
|   $uiDropdowns.filter('.upward').dropdown('setting', 'direction', 'upward'); | ||||
|  | ||||
|   $('.ui.checkbox').checkbox(); | ||||
|  | ||||
|   $('.tabular.menu .item').tab(); | ||||
|   $('.tabable.menu .item').tab(); | ||||
|  | ||||
|   $('.toggle.button').on('click', function () { | ||||
|     toggleElem($($(this).data('target'))); | ||||
|   | ||||
| @@ -6,27 +6,29 @@ const {appSubUrl, csrfToken} = window.config; | ||||
|  | ||||
| export function initRepoTopicBar() { | ||||
|   const mgrBtn = $('#manage_topic'); | ||||
|   if (!mgrBtn.length) return; | ||||
|   const editDiv = $('#topic_edit'); | ||||
|   const viewDiv = $('#repo-topics'); | ||||
|   const saveBtn = $('#save_topic'); | ||||
|   const topicDropdown = $('#topic_edit .dropdown'); | ||||
|   const topicForm = $('#topic_edit.ui.form'); | ||||
|   const topicPrompts = getPrompts(); | ||||
|   const topicForm = editDiv; // the old logic, editDiv is topicForm | ||||
|   const topicDropdownSearch = topicDropdown.find('input.search'); | ||||
|   const topicPrompts = { | ||||
|     countPrompt: topicDropdown.attr('data-text-count-prompt'), | ||||
|     formatPrompt: topicDropdown.attr('data-text-format-prompt'), | ||||
|   }; | ||||
|  | ||||
|   mgrBtn.on('click', () => { | ||||
|     hideElem(viewDiv); | ||||
|     showElem(editDiv); | ||||
|     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(editDiv); | ||||
|     showElem(viewDiv); | ||||
|     mgrBtn.focus(); | ||||
|   }); | ||||
|  | ||||
|   saveBtn.on('click', () => { | ||||
|     const topics = $('input[name=topics]').val(); | ||||
| @@ -39,13 +41,11 @@ export function initRepoTopicBar() { | ||||
|         viewDiv.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 = $('<a class="ui repo-topic large label topic"></a>'); | ||||
|             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); | ||||
| @@ -86,9 +86,6 @@ export function initRepoTopicBar() { | ||||
|       duration: 200, | ||||
|       variation: false, | ||||
|     }, | ||||
|     className: { | ||||
|       label: 'ui small label' | ||||
|     }, | ||||
|     apiSettings: { | ||||
|       url: `${appSubUrl}/explore/topics/search?q={query}`, | ||||
|       throttle: 500, | ||||
| @@ -101,7 +98,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('a.label.visible').each((_, el) => { | ||||
|           current_topics.push(el.getAttribute('data-value')); | ||||
|         }); | ||||
|  | ||||
|   | ||||
| @@ -88,21 +88,15 @@ import {initFormattingReplacements} from './features/formatting.js'; | ||||
| import {initCopyContent} from './features/copycontent.js'; | ||||
| import {initCaptcha} from './features/captcha.js'; | ||||
| import {initRepositoryActionView} from './components/RepoActionView.vue'; | ||||
| import {initAriaCheckboxPatch} from './modules/aria/checkbox.js'; | ||||
| import {initAriaDropdownPatch} from './modules/aria/dropdown.js'; | ||||
| import {initGlobalTooltips} from './modules/tippy.js'; | ||||
| import {initGiteaFomantic} from './modules/fomantic.js'; | ||||
|  | ||||
| // Run time-critical code as soon as possible. This is safe to do because this | ||||
| // script appears at the end of <body> and rendered HTML is accessible at that point. | ||||
| // TODO: replace them with CustomElements | ||||
| initFormattingReplacements(); | ||||
|  | ||||
| // Silence fomantic's error logging when tabs are used without a target content element | ||||
| $.fn.tab.settings.silent = true; | ||||
| // Disable the behavior of fomantic to toggle the checkbox when you press enter on a checkbox element. | ||||
| $.fn.checkbox.settings.enableEnterKey = false; | ||||
| // Use the patches to improve accessibility, these patches are designed to be as independent as possible, make it easy to modify or remove in the future. | ||||
| initAriaCheckboxPatch(); | ||||
| initAriaDropdownPatch(); | ||||
| // Init Gitea's Fomantic settings | ||||
| initGiteaFomantic(); | ||||
|  | ||||
| $(document).ready(() => { | ||||
|   initGlobalCommon(); | ||||
|   | ||||
							
								
								
									
										29
									
								
								web_src/js/modules/fomantic.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								web_src/js/modules/fomantic.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| import $ from 'jquery'; | ||||
| import {initAriaCheckboxPatch} from './aria/checkbox.js'; | ||||
| import {initAriaDropdownPatch} from './aria/dropdown.js'; | ||||
| import {svg} from '../svg.js'; | ||||
|  | ||||
| export function initGiteaFomantic() { | ||||
|   // Silence fomantic's error logging when tabs are used without a target content element | ||||
|   $.fn.tab.settings.silent = true; | ||||
|   // Disable the behavior of fomantic to toggle the checkbox when you press enter on a checkbox element. | ||||
|   $.fn.checkbox.settings.enableEnterKey = false; | ||||
|  | ||||
|   // Prevent Fomantic from guessing the popup direction. | ||||
|   // Otherwise, if the viewport height is small, Fomantic would show the popup upward, | ||||
|   // if the dropdown is at the beginning of the page, then the top part would be clipped by the window view, eg: Issue List "Sort" dropdown | ||||
|   $.fn.dropdown.settings.direction = 'downward'; | ||||
|   // By default, use "exact match" for full text search | ||||
|   $.fn.dropdown.settings.fullTextSearch = 'exact'; | ||||
|   // Do not use "cursor: pointer" for dropdown labels | ||||
|   $.fn.dropdown.settings.className.label += ' gt-cursor-default'; | ||||
|   // Always use Gitea's SVG icons | ||||
|   $.fn.dropdown.settings.templates.label = function(_value, text, preserveHTML, className) { | ||||
|     const escape = $.fn.dropdown.settings.templates.escape; | ||||
|     return escape(text, preserveHTML) + svg('octicon-x', 16, `${className.delete} icon`); | ||||
|   }; | ||||
|  | ||||
|   // Use the patches to improve accessibility, these patches are designed to be as independent as possible, make it easy to modify or remove in the future. | ||||
|   initAriaCheckboxPatch(); | ||||
|   initAriaDropdownPatch(); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 wxiaoguang
					wxiaoguang