diff options
-rw-r--r-- | .eslintrc.yml | 2 | ||||
-rw-r--r-- | content/404.html | 10 | ||||
-rw-r--r-- | content/assets/stylesheets/_variables.scss | 2 | ||||
-rw-r--r-- | content/assets/stylesheets/stylesheet.scss | 16 | ||||
-rw-r--r-- | content/frontend/bundles/404.js | 12 | ||||
-rw-r--r-- | content/frontend/bundles/archives.js | 32 | ||||
-rw-r--r-- | content/frontend/bundles/default.js | 8 | ||||
-rw-r--r-- | content/frontend/components/banner/banner.vue | 39 | ||||
-rw-r--r-- | content/frontend/components/version_banner/version_banner.vue | 14 | ||||
-rw-r--r-- | layouts/404.html | 1 | ||||
-rw-r--r-- | layouts/archives.html | 2 | ||||
-rw-r--r-- | layouts/default.html | 2 | ||||
-rw-r--r-- | spec/javascripts/components/banner/banner_spec.js | 35 |
13 files changed, 154 insertions, 21 deletions
diff --git a/.eslintrc.yml b/.eslintrc.yml index 189de0928..aa4628a99 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -9,4 +9,4 @@ parserOptions: rules: filenames/match-regex: - error - - "^[a-z_]+(\\.config|\\.[a-z_]+\\_spec)?$" + - "^[a-z0-9_]+(\\.config|\\.[a-z_]+\\_spec)?$" diff --git a/content/404.html b/content/404.html index 9ee14b952..2f22a8bbe 100644 --- a/content/404.html +++ b/content/404.html @@ -35,12 +35,4 @@ searchbar: false </div> </div> -<% if ENV['NANOC_ENV'] == 'production' %> -<script type="text/javascript"> - // Redirect to /archives on a non-existing versions - // Place here all offline versions as seen inside content/_data/versions.yaml - if (/10.3|10.4|10.5|10.6|10.7|10.8|11.0|11.1|11.2|11.3|11.4|11.5|11.6|11.7|11.8|11.9|11.10|11.11|12.0|12.1|12.2|12.3|12.4/.test(window.location.href)) { - window.location.replace("https://docs.gitlab.com/archives"); - } -</script> -<% end %> +<div data-archives-path="/archives/index.html?offline" data-environment="<%= ENV['NANOC_ENV'] %>" data-offline-versions="<%= @items['/_data/versions.yaml'][:offline].to_s.tr('[]" ', '') %>" id="offline-versions"></div> diff --git a/content/assets/stylesheets/_variables.scss b/content/assets/stylesheets/_variables.scss index fc3eca664..1076a506b 100644 --- a/content/assets/stylesheets/_variables.scss +++ b/content/assets/stylesheets/_variables.scss @@ -24,7 +24,7 @@ $nav-item-padding: 7px; // Heights $page-header-height: 53px; -$version-banner-height: 31px; +$banner-height: 31px; // GitLab colors // Tanuki diff --git a/content/assets/stylesheets/stylesheet.scss b/content/assets/stylesheets/stylesheet.scss index 348cb9472..6b8686609 100644 --- a/content/assets/stylesheets/stylesheet.scss +++ b/content/assets/stylesheets/stylesheet.scss @@ -290,8 +290,8 @@ li { } // main content -.wrapper.show-version-banner .main { - padding-top: calc(#{$page-header-height} + #{$version-banner-height}); +.wrapper.show-banner .main { + padding-top: calc(#{$page-header-height} + #{$banner-height}); } .main { @@ -443,14 +443,18 @@ li { color: $gds-white; } +.btn-close { + padding: 0 4px; +} + // Override Bootstrap tooltip .tooltip .tooltip-inner { font-size: $tooltip-font-size; } //global nav -.wrapper.show-version-banner .nav-wrapper { - padding-top: calc(#{$page-header-height} + #{$version-banner-height}); +.wrapper.show-banner .nav-wrapper { + padding-top: calc(#{$page-header-height} + #{$banner-height}); } .nav-wrapper { @@ -1802,11 +1806,11 @@ li { //end of in-page styles -.version-banner { +.banner { z-index: 5; line-height: 2; top: $page-header-height; - height: $version-banner-height; + height: $banner-height; background: $gds-gray-50; border-bottom: 1px solid $gds-gray-200; } diff --git a/content/frontend/bundles/404.js b/content/frontend/bundles/404.js new file mode 100644 index 000000000..6336f4b7d --- /dev/null +++ b/content/frontend/bundles/404.js @@ -0,0 +1,12 @@ +document.addEventListener( + 'DOMContentLoaded', + () => { + const { environment, offlineVersions, archivesPath } = document.getElementById('offline-versions').dataset; + const location = window.location.href; + const isOffline = offlineVersions.split(',').find(version => location.includes(version)); + + if(environment === 'production' && isOffline) { + window.location.replace(archivesPath); + } + } +); diff --git a/content/frontend/bundles/archives.js b/content/frontend/bundles/archives.js new file mode 100644 index 000000000..8b7ac2187 --- /dev/null +++ b/content/frontend/bundles/archives.js @@ -0,0 +1,32 @@ +import Vue from 'vue'; +import Banner from '../components/banner/banner.vue'; + +document.addEventListener( + 'DOMContentLoaded', + () => { + const urlParams = window.location.search; + const isOffline = urlParams.includes('?offline'); + + // eslint-disable-next-line no-new + new Vue({ + el: '#js-banner', + components: { + Banner, + }, + render(createElement) { + return createElement(Banner, { + props: { + text: 'You attempted to view an older version of the documentation that is no longer available on this site. Please select a newer version from the menu above or access an archive listed below.', + show: isOffline, + }, + on: { + toggle(isVisible) { + const wrapper = document.querySelector('.wrapper'); + wrapper.classList.toggle('show-banner', isVisible); + } + }, + }); + }, + }); + } +); diff --git a/content/frontend/bundles/default.js b/content/frontend/bundles/default.js index 6dc131a70..a13a18b67 100644 --- a/content/frontend/bundles/default.js +++ b/content/frontend/bundles/default.js @@ -17,7 +17,13 @@ document.addEventListener( }, render(createElement) { return createElement(VersionBanner, { - props: { isOutdated, latestVersionUrl, archivesUrl } + props: { isOutdated, latestVersionUrl, archivesUrl }, + on: { + toggleVersionBanner(isVisible) { + const wrapper = document.querySelector('.wrapper'); + wrapper.classList.toggle('show-banner', isVisible); + } + }, }); }, }); diff --git a/content/frontend/components/banner/banner.vue b/content/frontend/components/banner/banner.vue new file mode 100644 index 000000000..530bc9f0a --- /dev/null +++ b/content/frontend/components/banner/banner.vue @@ -0,0 +1,39 @@ +<script> +export default { + props: { + text: { + type: String, + required: false, + default: '', + }, + show: { + type: Boolean, + required: false, + default: true, + }, + }, + data() { + return { + isVisible: this.show + } + }, + mounted() { + this.toggleBanner(this.isVisible); + }, + methods: { + toggleBanner(isVisible) { + this.$emit('toggle', isVisible); + this.isVisible = isVisible; + }, + }, +}; +</script> + +<template> + <div v-if="isVisible" class="banner position-fixed w-100 text-center"> + <span v-if="text">{{ text }}</span> + <slot></slot> + <!-- TODO: Replace the 'x' below with a gl-icon component once gitlab-ui becomes available in the docs --> + <button class="btn btn-close pull-right" @click="toggleBanner(false)">x</button> + </div> +</template> diff --git a/content/frontend/components/version_banner/version_banner.vue b/content/frontend/components/version_banner/version_banner.vue index 97edd59c6..66d8fc40b 100644 --- a/content/frontend/components/version_banner/version_banner.vue +++ b/content/frontend/components/version_banner/version_banner.vue @@ -1,5 +1,10 @@ <script> +import Banner from '../banner/banner.vue'; + export default { + components: { + Banner, + }, props: { isOutdated: { type: Boolean, @@ -14,11 +19,16 @@ export default { required: true, }, }, + methods: { + toggleVersionBanner(isVisible) { + this.$emit('toggleVersionBanner', isVisible); + } + }, }; </script> <template> - <div v-if="isOutdated" class="version-banner position-fixed w-100 text-center"> + <banner :show="isOutdated" @toggle="toggleVersionBanner"> This is <a :href="archivesUrl">archived documentation</a> for GitLab. Go to <a :href="latestVersionUrl">the latest</a>. - </div> + </banner> </template> diff --git a/layouts/404.html b/layouts/404.html index e3f69414d..b437fbf13 100644 --- a/layouts/404.html +++ b/layouts/404.html @@ -18,6 +18,7 @@ <script type="application/javascript" src="<%= @items['/assets/javascripts/badges.*'].path %>"></script> <%= render '/docsearch.*' %> <script type="application/javascript" src="<%= @items['/assets/javascripts/404.*'].path %>"></script> + <script src="<%= @items['/frontend/bundles/404.*'].path %>"></script> <% if ENV['NANOC_ENV'] == 'production' %> <%# Add analytics only in production %> <%= render '/analytics.*' %> diff --git a/layouts/archives.html b/layouts/archives.html index 8252b4842..20ae661bf 100644 --- a/layouts/archives.html +++ b/layouts/archives.html @@ -6,6 +6,7 @@ <body> <%= render '/gtm.*' %> <%= render '/header.*' %> + <div id="js-banner"></div> <div class="wrapper"> <div class="main class js-main-wrapper"> <div class="js-article-content"> @@ -33,6 +34,7 @@ <script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script> <script type="application/javascript" src="<%= @items['/assets/javascripts/clipboardjs.*'].path %>"></script> <script type="application/javascript" src="<%= @items['/assets/javascripts/badges.*'].path %>"></script> + <script src="<%= @items['/frontend/bundles/archives.*'].path %>"></script> <%= render '/footer.*' %> <%= render '/docsearch.*' %> <% if ENV['NANOC_ENV'] == 'production' %> diff --git a/layouts/default.html b/layouts/default.html index c4e8463a2..05fa79931 100644 --- a/layouts/default.html +++ b/layouts/default.html @@ -10,7 +10,7 @@ <%= render '/header.*' %> <div id="js-version-banner" <%= 'data-is-outdated' if show_version_banner? %> data-latest-version-url="<%= @item.identifier.without_ext + '.html' %>" data-archives-url="/archives/"></div> - <div class="wrapper <%= 'show-version-banner' if show_version_banner? %>"> + <div class="wrapper"> <div class="nav-wrapper active"> <aside id="global-nav" class="global-nav"> <% if ENV['CI_PROJECT_NAME'] == 'gitlab-docs' or ENV['CI_PROJECT_NAME'].nil? %> diff --git a/spec/javascripts/components/banner/banner_spec.js b/spec/javascripts/components/banner/banner_spec.js new file mode 100644 index 000000000..e65cfbe3d --- /dev/null +++ b/spec/javascripts/components/banner/banner_spec.js @@ -0,0 +1,35 @@ +import { mount } from '@vue/test-utils'; +import Banner from '../../../../content/frontend/components/banner/banner.vue'; + +const propsData = { text: 'Some text', show: true }; + +describe('component: Banner', () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(Banner, { propsData, }); + }); + + it('renders a banner', () => { + expect(wrapper.exists('.banner')).toBe(true); + }); + + it('renders the correct banner text', () => { + const bannerText = wrapper.find('span'); + expect(bannerText.text()).toEqual(propsData.text); + }); + + it('renders a close button', () => { + expect(wrapper.exists('.btn-close')).toBe(true); + }); + + it('emits a toggle event on mount', () => { + expect(wrapper.emitted('toggle')[0]).toEqual([true]); + }); + + it('emits a toggle event when the close button is clicked', () => { + const closeBtn = wrapper.find('.btn-close'); + closeBtn.trigger('click'); + expect(wrapper.emitted('toggle')[1]).toEqual([false]); + }); +}); |