Commit 0e93b2da authored by Enrique Alcántara's avatar Enrique Alcántara

Merge branch '215121-style-toast-ui-editor' into 'master'

Style ToastUI editor to match design mockups

See merge request gitlab-org/gitlab!31351
parents 0895fbbd 22f42fce
import { __ } from '~/locale';
import { generateToolbarItem } from './toolbar_service';
/* eslint-disable @gitlab/require-i18n-strings */
const TOOLBAR_ITEM_CONFIGS = [
{ icon: 'heading', event: 'openHeadingSelect', classes: 'tui-heading', tooltip: __('Headings') },
{ icon: 'bold', command: 'Bold', tooltip: __('Add bold text') },
{ icon: 'italic', command: 'Italic', tooltip: __('Add italic text') },
{ icon: 'strikethrough', command: 'Strike', tooltip: __('Add strikethrough text') },
{ isDivider: true },
{ icon: 'quote', command: 'Blockquote', tooltip: __('Insert a quote') },
{ icon: 'link', event: 'openPopupAddLink', tooltip: __('Add a link') },
{ icon: 'doc-code', command: 'CodeBlock', tooltip: __('Insert a code block') },
{ isDivider: true },
{ icon: 'list-bulleted', command: 'UL', tooltip: __('Add a bullet list') },
{ icon: 'list-numbered', command: 'OL', tooltip: __('Add a numbered list') },
{ icon: 'list-task', command: 'Task', tooltip: __('Add a task list') },
{ icon: 'list-indent', command: 'Indent', tooltip: __('Indent') },
{ icon: 'list-outdent', command: 'Outdent', tooltip: __('Outdent') },
{ isDivider: true },
{ icon: 'dash', command: 'HR', tooltip: __('Add a line') },
{ icon: 'table', event: 'openPopupAddTable', classes: 'tui-table', tooltip: __('Add a table') },
{ isDivider: true },
{ icon: 'code', command: 'Code', tooltip: __('Insert inline code') },
];
export const EDITOR_OPTIONS = {
toolbarItems: [
'heading',
'bold',
'italic',
'strike',
'divider',
'quote',
'link',
'codeblock',
'divider',
'ul',
'ol',
'task',
'divider',
'hr',
'table',
'divider',
'code',
],
toolbarItems: TOOLBAR_ITEM_CONFIGS.map(config => generateToolbarItem(config)),
};
export const EDITOR_TYPES = {
......@@ -25,3 +33,5 @@ export const EDITOR_TYPES = {
};
export const EDITOR_HEIGHT = '100%';
export const EDITOR_PREVIEW_STYLE = 'horizontal';
......@@ -2,7 +2,7 @@
import 'codemirror/lib/codemirror.css';
import '@toast-ui/editor/dist/toastui-editor.css';
import { EDITOR_OPTIONS, EDITOR_TYPES, EDITOR_HEIGHT } from './constants';
import { EDITOR_OPTIONS, EDITOR_TYPES, EDITOR_HEIGHT, EDITOR_PREVIEW_STYLE } from './constants';
export default {
components: {
......@@ -31,6 +31,11 @@ export default {
required: false,
default: EDITOR_HEIGHT,
},
previewStyle: {
type: String,
required: false,
default: EDITOR_PREVIEW_STYLE,
},
},
computed: {
editorOptions() {
......@@ -52,6 +57,7 @@ export default {
ref="editor"
:initial-value="value"
:options="editorOptions"
:preview-style="previewStyle"
:initial-edit-type="initialEditType"
:height="height"
@change="onContentChanged"
......
<script>
import { GlIcon } from '@gitlab/ui';
export default {
components: {
GlIcon,
},
props: {
icon: {
type: String,
required: true,
},
},
};
</script>
<template>
<button class="p-0 gl-display-flex toolbar-button">
<gl-icon class="gl-mx-auto" :name="icon" />
</button>
</template>
import Vue from 'vue';
import ToolbarItem from './toolbar_item.vue';
const buildWrapper = propsData => {
const instance = new Vue({
render(createElement) {
return createElement(ToolbarItem, propsData);
},
});
instance.$mount();
return instance.$el;
};
// eslint-disable-next-line import/prefer-default-export
export const generateToolbarItem = config => {
const { icon, classes, event, command, tooltip, isDivider } = config;
if (isDivider) {
return 'divider';
}
return {
type: 'button',
options: {
el: buildWrapper({ props: { icon }, class: classes }),
event,
command,
tooltip,
},
};
};
// Overrides styles from ToastUI editor
.tui-editor-defaultUI-toolbar .toolbar-button {
color: $gl-gray-600;
border: 0;
&:hover,
&:active {
color: $blue-500;
border: 0;
}
}
......@@ -1188,6 +1188,9 @@ msgstr ""
msgid "Add a homepage to your wiki that contains information about your project and GitLab will display it here instead of this message."
msgstr ""
msgid "Add a line"
msgstr ""
msgid "Add a link"
msgstr ""
......@@ -1275,6 +1278,9 @@ msgstr ""
msgid "Add request manually"
msgstr ""
msgid "Add strikethrough text"
msgstr ""
msgid "Add system hook"
msgstr ""
......@@ -10943,6 +10949,9 @@ msgstr ""
msgid "Header message"
msgstr ""
msgid "Headings"
msgstr ""
msgid "Health"
msgstr ""
......@@ -11463,6 +11472,9 @@ msgstr ""
msgid "Incompatible options set!"
msgstr ""
msgid "Indent"
msgstr ""
msgid "Index all projects"
msgstr ""
......@@ -11487,12 +11499,18 @@ msgstr ""
msgid "Input your repository URL"
msgstr ""
msgid "Insert a code block"
msgstr ""
msgid "Insert a quote"
msgstr ""
msgid "Insert code"
msgstr ""
msgid "Insert inline code"
msgstr ""
msgid "Insert suggestion"
msgstr ""
......@@ -14653,6 +14671,9 @@ msgstr ""
msgid "OutdatedBrowser|You can provide feedback %{feedback_link_start}on this issue%{feedback_link_end} or via your usual support channels."
msgstr ""
msgid "Outdent"
msgstr ""
msgid "Overridden"
msgstr ""
......
......@@ -13,6 +13,9 @@ export const Editor = {
height: {
type: String,
},
previewStyle: {
type: String,
},
},
render(h) {
return h('div');
......
import { shallowMount } from '@vue/test-utils';
import RichContentEditor from '~/vue_shared/components/rich_content_editor/rich_content_editor.vue';
import {
EDITOR_OPTIONS,
EDITOR_TYPES,
EDITOR_HEIGHT,
EDITOR_PREVIEW_STYLE,
} from '~/vue_shared/components/rich_content_editor/constants';
describe('Rich Content Editor', () => {
let wrapper;
const editorOptions = {
toolbarItems: [
'heading',
'bold',
'italic',
'strike',
'divider',
'quote',
'link',
'codeblock',
'divider',
'ul',
'ol',
'task',
'divider',
'hr',
'table',
'divider',
'code',
],
};
const value = '## Some Markdown';
const findEditor = () => wrapper.find({ ref: 'editor' });
......@@ -44,15 +29,19 @@ describe('Rich Content Editor', () => {
});
it('provides the correct editor options', () => {
expect(findEditor().props().options).toEqual(editorOptions);
expect(findEditor().props().options).toEqual(EDITOR_OPTIONS);
});
it('has the correct preview style', () => {
expect(findEditor().props().previewStyle).toBe(EDITOR_PREVIEW_STYLE);
});
it('has the correct initial edit type', () => {
expect(findEditor().props().initialEditType).toBe('wysiwyg');
expect(findEditor().props().initialEditType).toBe(EDITOR_TYPES.wysiwyg);
});
it('has the correct height', () => {
expect(findEditor().props().height).toBe('100%');
expect(findEditor().props().height).toBe(EDITOR_HEIGHT);
});
});
......
import { shallowMount } from '@vue/test-utils';
import { GlIcon } from '@gitlab/ui';
import ToolbarItem from '~/vue_shared/components/rich_content_editor/toolbar_item.vue';
describe('Toolbar Item', () => {
let wrapper;
const findIcon = () => wrapper.find(GlIcon);
const findButton = () => wrapper.find('button');
const buildWrapper = propsData => {
wrapper = shallowMount(ToolbarItem, { propsData });
};
describe.each`
icon
${'heading'}
${'bold'}
${'italic'}
${'strikethrough'}
${'quote'}
${'link'}
${'doc-code'}
${'list-bulleted'}
${'list-numbered'}
${'list-task'}
${'list-indent'}
${'list-outdent'}
${'dash'}
${'table'}
${'code'}
`('toolbar item component', ({ icon }) => {
beforeEach(() => buildWrapper({ icon }));
it('renders a toolbar button', () => {
expect(findButton().exists()).toBe(true);
});
it(`renders the ${icon} icon`, () => {
expect(findIcon().exists()).toBe(true);
expect(findIcon().props().name).toBe(icon);
});
});
});
import { generateToolbarItem } from '~/vue_shared/components/rich_content_editor/toolbar_service';
describe('Toolbar Service', () => {
const config = {
icon: 'bold',
command: 'some-command',
tooltip: 'Some Tooltip',
event: 'some-event',
};
const generatedItem = generateToolbarItem(config);
it('generates the correct command', () => {
expect(generatedItem.options.command).toBe(config.command);
});
it('generates the correct tooltip', () => {
expect(generatedItem.options.tooltip).toBe(config.tooltip);
});
it('generates the correct event', () => {
expect(generatedItem.options.event).toBe(config.event);
});
it('generates a divider when isDivider is set to true', () => {
const isDivider = true;
expect(generateToolbarItem({ isDivider })).toBe('divider');
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment