summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/ide/components/shared/commit_message_field.vue
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/ide/components/shared/commit_message_field.vue')
-rw-r--r--app/assets/javascripts/ide/components/shared/commit_message_field.vue137
1 files changed, 137 insertions, 0 deletions
diff --git a/app/assets/javascripts/ide/components/shared/commit_message_field.vue b/app/assets/javascripts/ide/components/shared/commit_message_field.vue
new file mode 100644
index 00000000000..7fca7429ad7
--- /dev/null
+++ b/app/assets/javascripts/ide/components/shared/commit_message_field.vue
@@ -0,0 +1,137 @@
+<script>
+import { GlIcon, GlPopover } from '@gitlab/ui';
+import { __, sprintf } from '~/locale';
+import { MAX_TITLE_LENGTH, MAX_BODY_LENGTH } from '../../constants';
+
+export default {
+ components: {
+ GlIcon,
+ GlPopover,
+ },
+ props: {
+ text: {
+ type: String,
+ required: true,
+ },
+ placeholder: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ scrollTop: 0,
+ isFocused: false,
+ };
+ },
+ computed: {
+ allLines() {
+ return this.text.split('\n').map((line, i) => ({
+ text: line.substr(0, this.getLineLength(i)) || ' ',
+ highlightedText: line.substr(this.getLineLength(i)),
+ }));
+ },
+ },
+ methods: {
+ handleScroll() {
+ if (this.$refs.textarea) {
+ this.$nextTick(() => {
+ this.scrollTop = this.$refs.textarea.scrollTop;
+ });
+ }
+ },
+ getLineLength(i) {
+ return i === 0 ? MAX_TITLE_LENGTH : MAX_BODY_LENGTH;
+ },
+ onInput(e) {
+ this.$emit('input', e.target.value);
+ },
+ onCtrlEnter() {
+ if (!this.isFocused) return;
+ this.$emit('submit');
+ },
+ updateIsFocused(isFocused) {
+ this.isFocused = isFocused;
+ },
+ },
+ popoverOptions: {
+ triggers: 'hover',
+ placement: 'top',
+ content: sprintf(
+ __(`
+ The character highlighter helps you keep the subject line to %{titleLength} characters
+ and wrap the body at %{bodyLength} so they are readable in git.
+ `),
+ { titleLength: MAX_TITLE_LENGTH, bodyLength: MAX_BODY_LENGTH },
+ ),
+ },
+};
+</script>
+
+<template>
+ <fieldset
+ class="gl-rounded-base gl-inset-border-1-gray-400 gl-py-4 gl-px-5"
+ :class="{
+ 'gl-outline-none! gl-focus-ring-border-1-gray-900!': isFocused,
+ }"
+ >
+ <div
+ v-once
+ class="gl-display-flex gl-align-items-center gl-border-b-solid gl-border-b-1 gl-border-b-gray-100 gl-pb-3 gl-mb-3"
+ >
+ <div>{{ __('Commit Message') }}</div>
+ <div id="commit-message-popover-container">
+ <span id="commit-message-question" class="gl-gray-700 gl-ml-3">
+ <gl-icon name="question" />
+ </span>
+ <gl-popover
+ target="commit-message-question"
+ container="commit-message-popover-container"
+ v-bind="$options.popoverOptions"
+ />
+ </div>
+ </div>
+ <div class="gl-relative gl-w-full gl-h-13 gl-overflow-hidden">
+ <div class="gl-absolute gl-z-index-1 gl-font-monospace gl-text-transparent">
+ <div
+ data-testid="highlights"
+ :style="{
+ transform: `translate3d(0, ${-scrollTop}px, 0)`,
+ }"
+ >
+ <div v-for="(line, index) in allLines" :key="index">
+ <span
+ data-testid="highlights-text"
+ class="gl-white-space-pre-wrap gl-word-break-word"
+ v-text="line.text"
+ >
+ </span
+ ><mark
+ v-show="line.highlightedText"
+ data-testid="highlights-mark"
+ class="gl-px-1 gl-py-0 gl-bg-orange-100 gl-text-transparent gl-white-space-pre-wrap gl-word-break-word"
+ v-text="line.highlightedText"
+ >
+ </mark>
+ </div>
+ </div>
+ </div>
+ <textarea
+ ref="textarea"
+ :placeholder="placeholder"
+ :value="text"
+ class="gl-absolute gl-w-full gl-h-full gl-z-index-2 gl-font-monospace p-0 gl-outline-0 gl-bg-transparent gl-border-0"
+ data-qa-selector="ide_commit_message_field"
+ dir="auto"
+ name="commit-message"
+ @scroll="handleScroll"
+ @input="onInput"
+ @focus="updateIsFocused(true)"
+ @blur="updateIsFocused(false)"
+ @keydown.ctrl.enter="onCtrlEnter"
+ @keydown.meta.enter="onCtrlEnter"
+ >
+ </textarea>
+ </div>
+ </fieldset>
+</template>