diff --git a/app/assets/javascripts/content_editor/extensions/math_inline.js b/app/assets/javascripts/content_editor/extensions/math_inline.js new file mode 100644 index 00000000000..60f5288dcf6 --- /dev/null +++ b/app/assets/javascripts/content_editor/extensions/math_inline.js @@ -0,0 +1,35 @@ +import { Mark, markInputRule } from '@tiptap/core'; +import { __ } from '~/locale'; +import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants'; + +export const inputRegex = /(?:^|\s)\$`([^`]+)`\$$/gm; + +export default Mark.create({ + name: 'mathInline', + + parseHTML() { + return [ + { + tag: 'code.math[data-math-style=inline]', + priority: PARSE_HTML_PRIORITY_HIGHEST, + }, + ]; + }, + + renderHTML({ HTMLAttributes }) { + return [ + 'code', + { + title: __('Inline math'), + 'data-toggle': 'tooltip', + class: 'gl-inset-border-1-gray-400', + ...HTMLAttributes, + }, + 0, + ]; + }, + + addInputRules() { + return [markInputRule(inputRegex, this.type)]; + }, +}); diff --git a/app/assets/javascripts/content_editor/services/create_content_editor.js b/app/assets/javascripts/content_editor/services/create_content_editor.js index 616bcb9dc3a..385f1c63801 100644 --- a/app/assets/javascripts/content_editor/services/create_content_editor.js +++ b/app/assets/javascripts/content_editor/services/create_content_editor.js @@ -32,6 +32,7 @@ import Italic from '../extensions/italic'; import Link from '../extensions/link'; import ListItem from '../extensions/list_item'; import Loading from '../extensions/loading'; +import MathInline from '../extensions/math_inline'; import OrderedList from '../extensions/ordered_list'; import Paragraph from '../extensions/paragraph'; import Reference from '../extensions/reference'; @@ -106,6 +107,7 @@ export const createContentEditor = ({ Link, ListItem, Loading, + MathInline, OrderedList, Paragraph, Reference, diff --git a/app/assets/javascripts/content_editor/services/markdown_serializer.js b/app/assets/javascripts/content_editor/services/markdown_serializer.js index 8b6cff3f2e1..0dd3cb5b73f 100644 --- a/app/assets/javascripts/content_editor/services/markdown_serializer.js +++ b/app/assets/javascripts/content_editor/services/markdown_serializer.js @@ -27,6 +27,7 @@ import InlineDiff from '../extensions/inline_diff'; import Italic from '../extensions/italic'; import Link from '../extensions/link'; import ListItem from '../extensions/list_item'; +import MathInline from '../extensions/math_inline'; import OrderedList from '../extensions/ordered_list'; import Paragraph from '../extensions/paragraph'; import Reference from '../extensions/reference'; @@ -86,6 +87,11 @@ const defaultSerializerConfig = { : `](${state.esc(href)}${mark.attrs.title ? ` ${state.quote(mark.attrs.title)}` : ''})`; }, }, + [MathInline.name]: { + open: (...args) => `$${defaultMarkdownSerializer.marks.code.open(...args)}`, + close: (...args) => `${defaultMarkdownSerializer.marks.code.close(...args)}$`, + escape: false, + }, [Strike.name]: { open: '~~', close: '~~', diff --git a/app/assets/javascripts/issues_list/components/issues_list_app.vue b/app/assets/javascripts/issues_list/components/issues_list_app.vue index 93d9d2808e6..7b51f6ee46a 100644 --- a/app/assets/javascripts/issues_list/components/issues_list_app.vue +++ b/app/assets/javascripts/issues_list/components/issues_list_app.vue @@ -68,13 +68,6 @@ import { TOKEN_TITLE_TYPE, TOKEN_TITLE_WEIGHT, } from '~/vue_shared/components/filtered_search_bar/constants'; -import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue'; -import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue'; -import EpicToken from '~/vue_shared/components/filtered_search_bar/tokens/epic_token.vue'; -import IterationToken from '~/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue'; -import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue'; -import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue'; -import WeightToken from '~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue'; import eventHub from '../eventhub'; import reorderIssuesMutation from '../queries/reorder_issues.mutation.graphql'; import searchIterationsQuery from '../queries/search_iterations.query.graphql'; @@ -84,6 +77,20 @@ import searchUsersQuery from '../queries/search_users.query.graphql'; import IssueCardTimeInfo from './issue_card_time_info.vue'; import NewIssueDropdown from './new_issue_dropdown.vue'; +const AuthorToken = () => + import('~/vue_shared/components/filtered_search_bar/tokens/author_token.vue'); +const EmojiToken = () => + import('~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue'); +const EpicToken = () => import('~/vue_shared/components/filtered_search_bar/tokens/epic_token.vue'); +const IterationToken = () => + import('~/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue'); +const LabelToken = () => + import('~/vue_shared/components/filtered_search_bar/tokens/label_token.vue'); +const MilestoneToken = () => + import('~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue'); +const WeightToken = () => + import('~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue'); + export default { i18n, IssuableListTabs, diff --git a/app/assets/javascripts/releases/components/release_block.vue b/app/assets/javascripts/releases/components/release_block.vue index 3201ca1f443..b2bd405574f 100644 --- a/app/assets/javascripts/releases/components/release_block.vue +++ b/app/assets/javascripts/releases/components/release_block.vue @@ -1,4 +1,5 @@