Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-docs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--content/frontend/shared/components/gl_icon.vue60
-rw-r--r--content/frontend/shared/constants.js3
-rw-r--r--lib/filters/icons.rb2
-rw-r--r--lib/helpers/icons_helper.rb2
-rw-r--r--package.json1
-rw-r--r--rollup.config.js2
-rw-r--r--spec/frontend/shared/components/__snapshots__/gl_icon_spec.js.snap7
-rw-r--r--spec/frontend/shared/components/gl_icon_spec.js77
-rw-r--r--yarn.lock19
9 files changed, 171 insertions, 2 deletions
diff --git a/content/frontend/shared/components/gl_icon.vue b/content/frontend/shared/components/gl_icon.vue
new file mode 100644
index 00000000..d40aded1
--- /dev/null
+++ b/content/frontend/shared/components/gl_icon.vue
@@ -0,0 +1,60 @@
+<script>
+import data from '@gitlab/svgs/dist/icons.json';
+import iconSizeOptions from '../constants';
+
+let iconValidator = () => true;
+
+const { icons } = data;
+iconValidator = value => {
+ if (icons.includes(value)) {
+ return true;
+ }
+ // eslint-disable-next-line no-console
+ console.warn(`Icon '${value}' is not a known icon of @gitlab/svgs`);
+ return false;
+};
+
+/** This is a re-usable vue component for rendering a svg sprite icon
+ * @example
+ * <icon
+ * name="retry"
+ * :size="32"
+ * class="top"
+ * />
+ */
+export default {
+ props: {
+ name: {
+ type: String,
+ required: true,
+ validator: iconValidator,
+ },
+ size: {
+ type: Number,
+ required: false,
+ default: 16,
+ validator: value => iconSizeOptions.includes(value),
+ },
+ className: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+
+ computed: {
+ iconSizeClass() {
+ return this.size ? `s${this.size}` : '';
+ },
+ iconHref() {
+ return `#${this.name}`;
+ },
+ },
+};
+</script>
+
+<template>
+ <svg :class="['gl-icon', iconSizeClass, className]">
+ <use :href="iconHref" />
+ </svg>
+</template>
diff --git a/content/frontend/shared/constants.js b/content/frontend/shared/constants.js
new file mode 100644
index 00000000..ad764b74
--- /dev/null
+++ b/content/frontend/shared/constants.js
@@ -0,0 +1,3 @@
+const iconSizeOptions = [8, 10, 12, 14, 16, 18, 24, 32, 48, 72];
+
+export default iconSizeOptions;
diff --git a/lib/filters/icons.rb b/lib/filters/icons.rb
index 9b2292db..d695b7a2 100644
--- a/lib/filters/icons.rb
+++ b/lib/filters/icons.rb
@@ -28,6 +28,6 @@ class IconsFilter < Nanoc::Filter
end
def generate(icon, size, css_class)
- sprite_icon(icon, size, css_class)
+ icon(icon, size, css_class)
end
end
diff --git a/lib/helpers/icons_helper.rb b/lib/helpers/icons_helper.rb
index 9920e4f5..5c8410cc 100644
--- a/lib/helpers/icons_helper.rb
+++ b/lib/helpers/icons_helper.rb
@@ -12,7 +12,7 @@ module Nanoc::Helpers
%[<div class="d-none">#{read_file(sprite_path)}</div>]
end
- def sprite_icon(icon_name, size, css_class)
+ def icon(icon_name, size = nil, css_class = nil)
unless known_sprites.include?(icon_name)
exception = ArgumentError.new("#{icon_name} is not a known icon in @gitlab-org/gitlab-svg")
raise exception
diff --git a/package.json b/package.json
index 5b9f571a..961678e6 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"@babel/core": "^7.6.0",
"@babel/preset-env": "^7.6.0",
"@gitlab/eslint-config": "^1.6.0",
+ "@rollup/plugin-json": "^4.0.2",
"@vue/test-utils": "^1.0.0-beta.29",
"babel-core": "^7.0.0-bridge.0",
"babel-jest": "^24.9.0",
diff --git a/rollup.config.js b/rollup.config.js
index 8ce95b44..a53496c1 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -2,6 +2,7 @@ const importResolver = require('rollup-plugin-import-resolver');
const commonjs = require('rollup-plugin-commonjs');
const vue = require('rollup-plugin-vue');
const babel = require('rollup-plugin-babel');
+const json = require('@rollup/plugin-json');
const glob = require('glob');
function mapDirectory(file) {
@@ -18,6 +19,7 @@ module.exports = glob.sync('content/frontend/**/*.js').map(file => ({
plugins: [
commonjs(),
babel(),
+ json(),
vue(),
importResolver({
alias: {
diff --git a/spec/frontend/shared/components/__snapshots__/gl_icon_spec.js.snap b/spec/frontend/shared/components/__snapshots__/gl_icon_spec.js.snap
new file mode 100644
index 00000000..be478d99
--- /dev/null
+++ b/spec/frontend/shared/components/__snapshots__/gl_icon_spec.js.snap
@@ -0,0 +1,7 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`GlIcon component when created shows svg class "s8" and path "/path/to/icons.svg#check-circle" 1`] = `
+"<svg class=\\"gl-icon s8\\">
+ <use href=\\"#check-circle\\"></use>
+</svg>"
+`;
diff --git a/spec/frontend/shared/components/gl_icon_spec.js b/spec/frontend/shared/components/gl_icon_spec.js
new file mode 100644
index 00000000..81525e87
--- /dev/null
+++ b/spec/frontend/shared/components/gl_icon_spec.js
@@ -0,0 +1,77 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import GlIcon from '../../../../content/frontend/shared/components/gl_icon.vue';
+import iconSizeOptions from '../../../../content/frontend/shared/constants';
+
+const ICONS_PATH = '/path/to/icons.svg';
+const TEST_SIZE = 8;
+const TEST_NAME = 'check-circle';
+
+const localVue = createLocalVue();
+
+jest.mock('@gitlab/svgs/dist/icons.svg', () => '/path/to/icons.svg');
+
+describe('GlIcon component', () => {
+ let wrapper;
+ let consoleSpy;
+
+ const createComponent = props => {
+ wrapper = shallowMount(GlIcon, {
+ propsData: {
+ size: TEST_SIZE,
+ name: TEST_NAME,
+ ...props,
+ },
+ localVue,
+ });
+ };
+
+ const validateSize = size => GlIcon.props.size.validator(size);
+ const validateName = name => GlIcon.props.name.validator(name);
+
+ afterEach(() => {
+ wrapper.destroy();
+
+ if (consoleSpy) {
+ consoleSpy.mockRestore();
+ }
+ });
+
+ describe('when created', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it(`shows svg class "s${TEST_SIZE}" and path "${ICONS_PATH}#${TEST_NAME}"`, () => {
+ expect(wrapper.html()).toMatchSnapshot();
+ });
+ });
+
+ describe('size validator', () => {
+ const maxSize = Math.max(...iconSizeOptions);
+
+ it('fails with size outside options', () => {
+ expect(validateSize(maxSize + 10)).toBe(false);
+ });
+
+ it('passes with size in options', () => {
+ expect(validateSize(maxSize)).toBe(true);
+ });
+ });
+
+ describe('name validator', () => {
+ it('fails with name that does not exist', () => {
+ const badName = `${TEST_NAME}-bogus-zebra`;
+ consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
+
+ expect(validateName(badName)).toBe(false);
+
+ expect(consoleSpy).toHaveBeenCalledWith(
+ `Icon '${badName}' is not a known icon of @gitlab/svgs`,
+ );
+ });
+
+ it('passes with name that exists', () => {
+ expect(validateName(TEST_NAME)).toBe(true);
+ });
+ });
+});
diff --git a/yarn.lock b/yarn.lock
index 68924c70..e9e67799 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -882,6 +882,20 @@
"@types/istanbul-reports" "^1.1.1"
"@types/yargs" "^13.0.0"
+"@rollup/plugin-json@^4.0.2":
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@rollup/plugin-json/-/plugin-json-4.0.2.tgz#482185ee36ac7dd21c346e2dbcc22ffed0c6f2d6"
+ integrity sha512-t4zJMc98BdH42mBuzjhQA7dKh0t4vMJlUka6Fz0c+iO5IVnWaEMiYBy1uBj9ruHZzXBW23IPDGL9oCzBkQ9Udg==
+ dependencies:
+ "@rollup/pluginutils" "^3.0.4"
+
+"@rollup/pluginutils@^3.0.4":
+ version "3.0.8"
+ resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.0.8.tgz#4e94d128d94b90699e517ef045422960d18c8fde"
+ integrity sha512-rYGeAc4sxcZ+kPG/Tw4/fwJODC3IXHYDH4qusdN/b6aLw5LPUbzpecYbEJh4sVQGPFJxd2dBU4kc1H3oy9/bnw==
+ dependencies:
+ estree-walker "^1.0.1"
+
"@types/babel-types@*", "@types/babel-types@^7.0.0":
version "7.0.7"
resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.7.tgz#667eb1640e8039436028055737d2b9986ee336e3"
@@ -2289,6 +2303,11 @@ estree-walker@^0.6.1:
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362"
integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==
+estree-walker@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
+ integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
+
esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"