diff --git a/app/helpers/dropdowns_helper.rb b/app/helpers/dropdowns_helper.rb index 0092743f96ef1559049b465afe2223f370c088e4..a910d3d7c9d4d79eadda4dc102c272567aa47fec 100644 --- a/app/helpers/dropdowns_helper.rb +++ b/app/helpers/dropdowns_helper.rb @@ -129,7 +129,7 @@ def dropdown_footer(add_content_class: false, &block) end def dropdown_loading - spinner = loading_icon(container: true, size: "md", css_class: "gl-mt-7") + spinner = gl_loading_icon(size: "md", css_class: "gl-mt-7") content_tag(:div, spinner, class: "dropdown-loading") end end diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index 32d808c960c0b3042907c1b25dbc84c28ce7f051..6f7ac069fe4878eba1d9f314f43dfe969dc40529 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -49,13 +49,39 @@ def sprite_icon(icon_name, size: DEFAULT_ICON_SIZE, css_class: nil) end end - def loading_icon(container: false, color: 'orange', size: 'sm', css_class: nil) - css_classes = ['gl-spinner', "gl-spinner-#{color}", "gl-spinner-#{size}"] - css_classes << "#{css_class}" unless css_class.blank? - - spinner = content_tag(:span, "", { class: css_classes.join(' '), aria: { label: _('Loading') } }) - - container == true ? content_tag(:div, spinner, { class: 'gl-spinner-container' }) : spinner + # Creates a GitLab UI loading icon/spinner. + # + # Examples: + # # Default + # gl_loading_icon + # + # # Sizes + # gl_loading_icon(size: 'md') + # gl_loading_icon(size: 'lg') + # gl_loading_icon(size: 'xl') + # + # # Colors + # gl_loading_icon(color: 'light') + # + # # Block/Inline + # gl_loading_icon(inline: true) + # + # # Custom classes + # gl_loading_icon(css_class: "foo-bar") + # + # See also https://gitlab-org.gitlab.io/gitlab-ui/?path=/story/base-loading-icon--default + def gl_loading_icon(inline: false, color: 'dark', size: 'sm', css_class: nil) + spinner = content_tag(:span, "", { + class: %[gl-spinner gl-spinner-#{color} gl-spinner-#{size} gl-vertical-align-text-bottom!], + aria: { label: _('Loading') } + }) + + container_classes = ['gl-spinner-container'] + container_classes << css_class unless css_class.blank? + content_tag(inline ? :span : :div, spinner, { + class: container_classes, + role: 'status' + }) end def external_snippet_icon(name) diff --git a/app/views/projects/_files.html.haml b/app/views/projects/_files.html.haml index 2f4a61865f85e7f9646c8a58a5af57244725ed3b..a7cf50623f0c927ecb871ff604daafbc84cdf8f1 100644 --- a/app/views/projects/_files.html.haml +++ b/app/views/projects/_files.html.haml @@ -12,8 +12,7 @@ .info-well.gl-display-none.gl-sm-display-flex.project-last-commit.gl-flex-direction-column #js-last-commit.gl-m-auto - .gl-spinner-container.m-auto - = loading_icon(size: 'md', color: 'dark', css_class: 'align-text-bottom') + = gl_loading_icon(size: 'md') #js-code-owners - if is_project_overview diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml index 919cafe7ce8aed5104028071d1055bd75941ca90..85b9a69ab4cc67945f83b8bc0f09abf1390e3c0e 100644 --- a/app/views/projects/blob/_blob.html.haml +++ b/app/views/projects/blob/_blob.html.haml @@ -21,8 +21,7 @@ project_path: @project.full_path, target_branch: project.empty_repo? ? ref : @ref, original_branch: @ref } } - .gl-spinner-container - = loading_icon(size: 'md') + = gl_loading_icon(size: 'md') - else %article.file-holder = render 'projects/blob/header', blob: blob diff --git a/app/views/projects/blob/viewers/_gitlab_ci_yml_loading.html.haml b/app/views/projects/blob/viewers/_gitlab_ci_yml_loading.html.haml index cf57f1b531d7ea9313f14557c73287a58eb7d191..2b8f62d98bf88b6230ea180d3427e93790995cac 100644 --- a/app/views/projects/blob/viewers/_gitlab_ci_yml_loading.html.haml +++ b/app/views/projects/blob/viewers/_gitlab_ci_yml_loading.html.haml @@ -1,4 +1,4 @@ -= loading_icon(css_class: "gl-vertical-align-text-bottom mr-1") += gl_loading_icon(inline: true, css_class: "gl-mr-2!") = s_('Pipelines|Validating GitLab CI configuration…') = link_to _('Learn more'), help_page_path('ci/yaml/index') diff --git a/app/views/projects/blob/viewers/_loading.html.haml b/app/views/projects/blob/viewers/_loading.html.haml index 18fd0d87ce63d4fe69921439194038da9f2245b1..9cb934da7c0a010f7f53aa239fc0a136a6e804b5 100644 --- a/app/views/projects/blob/viewers/_loading.html.haml +++ b/app/views/projects/blob/viewers/_loading.html.haml @@ -1,2 +1 @@ -.text-center.gl-mt-4.gl-mb-3 - = loading_icon(size: "md", css_class: "qa-spinner") += gl_loading_icon(size: "md", css_class: "qa-spinner gl-my-4") diff --git a/app/views/projects/blob/viewers/_loading_auxiliary.html.haml b/app/views/projects/blob/viewers/_loading_auxiliary.html.haml index 5a2212e0b4eb511141918dfafb78853407087561..19aa96a930220dd45b9fdca0ba5212ab7b8f007d 100644 --- a/app/views/projects/blob/viewers/_loading_auxiliary.html.haml +++ b/app/views/projects/blob/viewers/_loading_auxiliary.html.haml @@ -1,2 +1,2 @@ -= loading_icon(css_class: "gl-vertical-align-text-bottom") += gl_loading_icon(inline: true) = _("Analyzing file…") diff --git a/app/views/projects/blob/viewers/_metrics_dashboard_yml_loading.html.haml b/app/views/projects/blob/viewers/_metrics_dashboard_yml_loading.html.haml index db4b04eaeb8803f0a2b8b4a14a6ef2d360af63dd..5e355ecc4b8ccad705e9588614d85238b36f5a51 100644 --- a/app/views/projects/blob/viewers/_metrics_dashboard_yml_loading.html.haml +++ b/app/views/projects/blob/viewers/_metrics_dashboard_yml_loading.html.haml @@ -1,4 +1,4 @@ -= loading_icon(css_class: "gl-vertical-align-text-bottom mr-1") += gl_loading_icon(inline: true, css_class: "mr-1") = _('Metrics Dashboard YAML definition') + '…' = link_to _('Learn more'), help_page_path('operations/metrics/dashboards/yaml.md') diff --git a/app/views/projects/blob/viewers/_route_map_loading.html.haml b/app/views/projects/blob/viewers/_route_map_loading.html.haml index c48ab84654f0ce17b2d4594d4f50e11ddc33c9c8..d9e965246a82820d48945b0821f897f580c81069 100644 --- a/app/views/projects/blob/viewers/_route_map_loading.html.haml +++ b/app/views/projects/blob/viewers/_route_map_loading.html.haml @@ -1,4 +1,4 @@ -= loading_icon(css_class: "gl-vertical-align-text-bottom gl-mr-1") += gl_loading_icon(inline: true, css_class: "gl-mr-1") Validating Route Map… = link_to 'Learn more', help_page_path('ci/environments/index.md', anchor: 'go-from-source-files-to-public-pages') diff --git a/app/views/projects/blob/viewers/_sketch.html.haml b/app/views/projects/blob/viewers/_sketch.html.haml index 08c21258d3fc858586a1064802dc1a03004909cc..4feaa7392fd74fb25fa25adc4df15c65e5da3df5 100644 --- a/app/views/projects/blob/viewers/_sketch.html.haml +++ b/app/views/projects/blob/viewers/_sketch.html.haml @@ -1,3 +1,2 @@ .file-content#js-sketch-viewer{ data: { endpoint: blob_raw_path } } - .text-center.gl-mt-4.gl-mb-3.js-loading-icon - = loading_icon(size: "md") + = gl_loading_icon(size: "md", css_class: "gl-my-4 js-loading-icon") diff --git a/app/views/projects/blob/viewers/_stl.html.haml b/app/views/projects/blob/viewers/_stl.html.haml index f98deebacf9ff8da5ff214d8b37bb33689faf095..8bf0339fc3c1e00eee3a88d8d8856e91b351f416 100644 --- a/app/views/projects/blob/viewers/_stl.html.haml +++ b/app/views/projects/blob/viewers/_stl.html.haml @@ -1,6 +1,6 @@ .file-content.is-stl-loading .text-center#js-stl-viewer{ data: { endpoint: blob_raw_path } } - = loading_icon(size: "md", css_class: "gl-mt-4 gl-mb-3") + = gl_loading_icon(size: "md", css_class: "gl-my-4") .text-center.gl-mt-3.gl-mb-3.stl-controls .btn-group %button.gl-button.btn.btn-default.btn-sm.js-material-changer{ data: { type: 'wireframe' } } diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index 22a5bada3117b4fb28addc2698bf7d03f973a7fb..36641a8c508fd6f6e0e4843ce7d0e755c3e265da 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -34,5 +34,4 @@ %div{ id: dom_id(@project) } %ol#commits-list.list-unstyled.content_list = render 'commits', project: @project, ref: @ref - .loading.hide - = loading_icon(size: "lg") + = gl_loading_icon(size: 'lg', css_class: 'loading hide') diff --git a/app/views/projects/find_file/show.html.haml b/app/views/projects/find_file/show.html.haml index 194b10e9ef4f7c655976c0df977b2f2ed80dddf0..af5ad06d30e8d3600b20b36fab7acaab60b162f4 100644 --- a/app/views/projects/find_file/show.html.haml +++ b/app/views/projects/find_file/show.html.haml @@ -23,5 +23,4 @@ = _('There are no matching files') %p.text-secondary = _('Try using a different search term to find the file you are looking for.') - .text-center.gl-mt-3.loading - = loading_icon(size: 'md') + = gl_loading_icon(size: 'md', css_class: 'gl-mt-3 loading') diff --git a/app/views/projects/imports/show.html.haml b/app/views/projects/imports/show.html.haml index 0c1efab21951fb8ed993e29fb05aecff6547a498..8096bc6cead940c161f60b303e108fb0825d646f 100644 --- a/app/views/projects/imports/show.html.haml +++ b/app/views/projects/imports/show.html.haml @@ -4,7 +4,7 @@ .save-project-loader .center %h2 - = loading_icon + = gl_loading_icon(inline: true) = import_in_progress_title - if !has_ci_cd_only_params? && @project.external_import? %p.monospace git clone --bare #{@project.safe_import_url} diff --git a/app/views/projects/services/prometheus/_custom_metrics.html.haml b/app/views/projects/services/prometheus/_custom_metrics.html.haml index 4586ee844c0b7cb3802dc85d71e912931f24cd4e..896249c6163cab25de92a759d9de718ccbcb224b 100644 --- a/app/views/projects/services/prometheus/_custom_metrics.html.haml +++ b/app/views/projects/services/prometheus/_custom_metrics.html.haml @@ -18,7 +18,7 @@ .flash-text .loading-metrics.js-loading-custom-metrics %p.m-3 - = loading_icon(css_class: 'metrics-load-spinner') + = gl_loading_icon(inline: true, css_class: 'metrics-load-spinner') = s_('PrometheusService|Finding custom metrics...') .empty-metrics.hidden.js-empty-custom-metrics %p.text-tertiary.m-3.js-no-active-integration-text.hidden diff --git a/app/views/projects/services/prometheus/_metrics.html.haml b/app/views/projects/services/prometheus/_metrics.html.haml index 0d41584652f95ebb66acb2d1b58454250d9515c8..8794f3e24dae2075b6626f330720cb81e5eb7b49 100644 --- a/app/views/projects/services/prometheus/_metrics.html.haml +++ b/app/views/projects/services/prometheus/_metrics.html.haml @@ -16,7 +16,7 @@ .card-body .loading-metrics.js-loading-metrics %p.m-3 - = loading_icon(css_class: 'metrics-load-spinner') + = gl_loading_icon(inline: true, css_class: 'metrics-load-spinner') = s_('PrometheusService|Finding and configuring metrics...') .empty-metrics.hidden.js-empty-metrics %p.text-tertiary.m-3 diff --git a/app/views/shared/_new_project_item_select.html.haml b/app/views/shared/_new_project_item_select.html.haml index 08003346d09043573b023ca336d2a884ec56bb4f..74a397d7a03f4611adb42cd3e7ba1b5bfcd93c6c 100644 --- a/app/views/shared/_new_project_item_select.html.haml +++ b/app/views/shared/_new_project_item_select.html.haml @@ -1,7 +1,7 @@ - if any_projects?(@projects) .project-item-select-holder.btn-group.gl-ml-auto.gl-mr-auto.gl-relative.gl-overflow-hidden{ class: 'gl-display-flex!' } %a.btn.gl-button.btn-confirm.js-new-project-item-link.block-truncated.qa-new-project-item-link{ href: '', data: { label: local_assigns[:label], type: local_assigns[:type] }, class: "gl-m-0!" } - = loading_icon(color: 'light') + = gl_loading_icon(inline: true, color: 'light') = project_select_tag :project_path, class: "project-item-select gl-absolute! gl-visibility-hidden", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at', relative_path: local_assigns[:path], with_shared: local_assigns[:with_shared], include_projects_in_subgroups: local_assigns[:include_projects_in_subgroups] }, with_feature_enabled: local_assigns[:with_feature_enabled] %button.btn.dropdown-toggle.btn-confirm.btn-md.gl-button.gl-dropdown-toggle.dropdown-toggle-split.new-project-item-select-button.qa-new-project-item-select-button.gl-p-0.gl-w-100{ class: "gl-m-0!", 'aria-label': _('Toggle project select') } = sprite_icon('chevron-down') diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index 7787e5dd66080d020cd0a44132ff2899ecd3e151..f966958d2c73c687dc9db4fcd5d8459fac999a16 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -50,7 +50,7 @@ // Fallback while content is loading .title.hide-collapsed = _('Time tracking') - = loading_icon(css_class: 'gl-vertical-align-text-bottom') + = gl_loading_icon(inline: true) - if issuable_sidebar.has_key?(:due_date) #js-due-date-entry-point @@ -109,8 +109,8 @@ = dropdown_loading = dropdown_footer add_content_class: true do %button.gl-button.btn.btn-confirm.sidebar-move-issue-confirmation-button.js-move-issue-confirmation-button{ type: 'button', disabled: true } + = gl_loading_icon(inline: true, css_class: 'sidebar-move-issue-confirmation-loading-icon gl-mr-2') = _('Move') - = loading_icon(css_class: 'gl-vertical-align-text-bottom sidebar-move-issue-confirmation-loading-icon') -# haml-lint:disable InlineJavaScript %script.js-sidebar-options{ type: "application/json" }= issuable_sidebar_options(issuable_sidebar).to_json.html_safe diff --git a/app/views/shared/issuable/_sidebar_assignees.html.haml b/app/views/shared/issuable/_sidebar_assignees.html.haml index 9a0b25f401536390c8a615fb0753d8b15426dcc0..2fd4c598580c23a31cef3de145653b6f5bcf4f2d 100644 --- a/app/views/shared/issuable/_sidebar_assignees.html.haml +++ b/app/views/shared/issuable/_sidebar_assignees.html.haml @@ -7,7 +7,7 @@ directly_invite_members: can_admin_project_member?(@project) } } .title.hide-collapsed = _('Assignee') - = loading_icon(css_class: 'gl-vertical-align-text-bottom') + = gl_loading_icon(inline: true) .js-sidebar-assignee-data.selectbox.hide-collapsed - if assignees.none? diff --git a/app/views/shared/issuable/_sidebar_reviewers.html.haml b/app/views/shared/issuable/_sidebar_reviewers.html.haml index bc76d292dd64b207361249f5198ab186fdd5d57a..ce252e7457081c2ec8904ad90e6c3b6e5438aa39 100644 --- a/app/views/shared/issuable/_sidebar_reviewers.html.haml +++ b/app/views/shared/issuable/_sidebar_reviewers.html.haml @@ -3,7 +3,7 @@ #js-vue-sidebar-reviewers{ data: { field: issuable_type, signed_in: signed_in } } .title.hide-collapsed = _('Reviewer') - = loading_icon(css_class: 'gl-vertical-align-text-bottom') + = gl_loading_icon(inline: true) .selectbox.hide-collapsed - if reviewers.none? diff --git a/app/views/shared/notes/_hints.html.haml b/app/views/shared/notes/_hints.html.haml index 6c8b2a9e5bb392dbb110744ec01bc8333c6ec304..8a79a17b16653d47bd31998fae38d501828f349c 100644 --- a/app/views/shared/notes/_hints.html.haml +++ b/app/views/shared/notes/_hints.html.haml @@ -18,7 +18,7 @@ %span.attaching-file-message -# Populated by app/assets/javascripts/dropzone_input.js %span.uploading-progress 0% - = loading_icon(css_class: 'align-text-bottom gl-mr-2') + = gl_loading_icon(inline: true, css_class: 'gl-mr-2') %span.uploading-error-container.hide %span.uploading-error-icon diff --git a/doc/development/fe_guide/icons.md b/doc/development/fe_guide/icons.md index 3f7490b0221aae0b246f9f90b3a2facef28da833..d107af156db631a9f02f3c8f6b73c2e90639cb05 100644 --- a/doc/development/fe_guide/icons.md +++ b/doc/development/fe_guide/icons.md @@ -88,50 +88,36 @@ Please use the following function inside JS to render an icon: ### Usage in HAML/Rails -To insert a loading spinner in HAML or Rails use the `loading_icon` helper: +To insert a loading spinner in HAML or Rails use the `gl_loading_icon` helper: ```haml -= loading_icon += gl_loading_icon ``` -You can include one or more of the following properties with the `loading_icon` helper, as demonstrated +You can include one or more of the following properties with the `gl_loading_icon` helper, as demonstrated by the examples that follow: -- `container` (optional): wraps the loading icon in a container, which centers the loading icon using the `text-center` CSS property. -- `color` (optional): either `orange` (default), `light`, or `dark`. +- `inline` (optional): uses in an inline element if `true`, otherwise, a block element (default), with the spinner centered. +- `color` (optional): either `dark` (default) or `light`. - `size` (optional): either `sm` (default), `md`, `lg`, or `xl`. -- `css_class` (optional): defaults to an empty string, but can be used for utility classes to fine-tune alignment or spacing. +- `css_class` (optional): defaults to nothing, but can be used for utility classes to fine-tune alignment or spacing. **Example 1:** The following HAML expression generates a loading icon's markup and -centers the icon by wrapping it in a `gl-spinner-container` element. +centers the icon. ```haml -= loading_icon(container: true) -``` - -**Output from example 1:** - -```html -<div class="gl-spinner-container"> - <span class="gl-spinner gl-spinner-orange gl-spinner-sm" aria-label="Loading"></span> -</div> += gl_loading_icon ``` **Example 2:** -The following HAML expression generates a loading icon's markup +The following HAML expression generates an inline loading icon's markup with a custom size. It also appends a margin utility class. ```haml -= loading_icon(size: 'lg', css_class: 'gl-mr-2') -``` - -**Output from example 2:** - -```html -<span class="gl-spinner gl-spinner-orange gl-spinner-lg gl-mr-2" aria-label="Loading"></span> += gl_loading_icon(inline: true, size: 'lg', css_class: 'gl-mr-2') ``` ### Usage in Vue diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb index af2957d72c7bc7b184f12dccdbce4607631c49bb..139e8be33d54ad09915ef213308093caedbc71d1 100644 --- a/spec/helpers/icons_helper_spec.rb +++ b/spec/helpers/icons_helper_spec.rb @@ -231,23 +231,33 @@ end end - describe 'loading_icon' do - it 'returns span with gl-spinner class and default configuration' do - expect(loading_icon.to_s) - .to eq '<span class="gl-spinner gl-spinner-orange gl-spinner-sm" aria-label="Loading"></span>' + describe 'gl_loading_icon' do + it 'returns the default spinner markup' do + expect(gl_loading_icon.to_s) + .to eq '<div class="gl-spinner-container" role="status"><span class="gl-spinner gl-spinner-dark gl-spinner-sm gl-vertical-align-text-bottom!" aria-label="Loading"></span></div>' end context 'when css_class is provided' do - it 'appends css_class to gl-spinner element' do - expect(loading_icon(css_class: 'gl-mr-2').to_s) - .to eq '<span class="gl-spinner gl-spinner-orange gl-spinner-sm gl-mr-2" aria-label="Loading"></span>' + it 'appends css_class to container element' do + expect(gl_loading_icon(css_class: 'gl-mr-2').to_s).to match 'gl-spinner-container gl-mr-2' end end - context 'when container is true' do - it 'creates a container that has the gl-spinner-container class selector' do - expect(loading_icon(container: true).to_s) - .to eq '<div class="gl-spinner-container"><span class="gl-spinner gl-spinner-orange gl-spinner-sm" aria-label="Loading"></span></div>' + context 'when size is provided' do + it 'sets the size class' do + expect(gl_loading_icon(size: 'xl').to_s).to match 'gl-spinner-xl' + end + end + + context 'when color is provided' do + it 'sets the color class' do + expect(gl_loading_icon(color: 'light').to_s).to match 'gl-spinner-light' + end + end + + context 'when inline is true' do + it 'creates an inline container' do + expect(gl_loading_icon(inline: true).to_s).to start_with '<span class="gl-spinner-container"' end end end