Commit 22f42fce authored by Jacques Erasmus's avatar Jacques Erasmus Committed by Enrique Alcántara

Style ToastUI editor to match mockups

Styled the ToastUI editor to match the design mockups
parent 86878d87
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 ""
......@@ -10940,6 +10946,9 @@ msgstr ""
msgid "Header message"
msgstr ""
msgid "Headings"
msgstr ""
msgid "Health"
msgstr ""
......@@ -11460,6 +11469,9 @@ msgstr ""
msgid "Incompatible options set!"
msgstr ""
msgid "Indent"
msgstr ""
msgid "Index all projects"
msgstr ""
......@@ -11484,12 +11496,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 ""
......@@ -14644,6 +14662,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