Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ const MESSAGES = {
context: 'Option to set text format to header 3',
},

// Text alignments
alignLeft: {
message: 'Align left',
context: 'Button to align text to the left',
},
alignRight: {
message: 'Align right',
context: 'Button to align text to the right',
},

// Accessibility labels
textFormattingToolbar: {
message: 'Text formatting toolbar',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,20 @@

<ToolbarDivider v-if="visibleCategories.includes('clipboard')" />

<!-- Text Alignment -->
<ToolbarButton
v-if="visibleCategories.includes('align')"
:title="alignAction.title"
:icon="alignAction.icon"
:is-active="alignAction.isActive"
:is-available="alignAction.isAvailable"
@click="alignAction.handler"
/>

<ToolbarDivider v-if="visibleCategories.includes('align')" />

<!-- Clear Formatting -->

<ToolbarButton
v-if="visibleCategories.includes('clearFormat')"
:title="clearFormatting$()"
Expand Down Expand Up @@ -221,6 +235,25 @@
</button>
</template>

<!-- Overflow Text Alignment -->
<template v-if="overflowCategories.includes('align')">
<button
class="dropdown-item"
:class="{ active: alignAction.isActive }"
role="menuitem"
:disabled="alignAction.isAvailable"
@click="alignAction.handler"
>
<img
:src="alignAction.icon"
class="dropdown-item-icon"
alt=""
aria-hidden="true"
>
<span class="dropdown-item-text">{{ alignAction.title }}</span>
</button>
</template>

<!-- Overflow Clear Format -->
<template v-if="overflowCategories.includes('clearFormat')">
<button
Expand Down Expand Up @@ -345,6 +378,7 @@
script: 710,
lists: 650,
clearFormat: 560,
align: 530,
clipboard: 500,
textFormat: 400,
};
Expand All @@ -355,6 +389,7 @@
'script',
'lists',
'clearFormat',
'align',
'clipboard',
'textFormat',
];
Expand All @@ -365,6 +400,7 @@
canClearFormat,
historyActions,
textActions,
alignAction,
listActions,
scriptActions,
insertTools,
Expand Down Expand Up @@ -523,6 +559,7 @@
canClearFormat,
historyActions,
textActions,
alignAction,
listActions,
scriptActions,
insertTools,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>

<NodeViewWrapper class="image-node-wrapper">
<NodeViewWrapper :style="wrapperStyle">
<div
ref="containerRef"
class="image-node-view"
Expand Down Expand Up @@ -88,6 +88,21 @@
const compactThreshold = 200;
let resizeListeners = null;

// Compute wrapper style based on textAlign attribute
const wrapperStyle = computed(() => {
const align = props.node.attrs.textAlign || 'left';
const alignmentMap = {
left: 'flex-start',
center: 'center',
right: 'flex-end',
justify: 'flex-start',
};
return {
display: 'flex',
justifyContent: alignmentMap[align] || 'flex-start',
};
});

// Create debounced version of saveSize function
const debouncedSaveSize = debounce(() => {
props.updateAttributes({
Expand Down Expand Up @@ -296,6 +311,7 @@
containerRef,
resizeHandleRef,
styleWidth,
wrapperStyle,
onResizeStart,
removeImage,
editImage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@
@click="action.handler"
/>
<ToolbarDivider />
<ToolbarButton
:title="alignAction.title"
:icon="alignAction.icon"
:is-active="alignAction.isActive"
@click="alignAction.handler"
/>
<ToolbarDivider />
<ToolbarButton
v-for="action in scriptActions"
:key="action.name"
Expand Down Expand Up @@ -131,7 +138,8 @@
textFormattingToolbar$,
} = getTipTapEditorStrings();

const { textActions, listActions, scriptActions, insertTools } = useToolbarActions(emit);
const { textActions, listActions, scriptActions, insertTools, alignAction } =
useToolbarActions(emit);

const { canIncreaseFormat, canDecreaseFormat, increaseFormat, decreaseFormat } =
useFormatControls();
Expand Down Expand Up @@ -200,6 +208,7 @@
listActions,
scriptActions,
insertTools,
alignAction,
toggleToolbar,
canIncreaseFormat,
canDecreaseFormat,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Editor } from '@tiptap/vue-2';
import StarterKitExtension from '@tiptap/starter-kit';
import { Superscript } from '@tiptap/extension-superscript';
import { Subscript } from '@tiptap/extension-subscript';
import { TextAlign } from '@tiptap/extension-text-align';
import { Small } from '../extensions/SmallTextExtension';
import { Image } from '../extensions/Image';
import { CodeBlockSyntaxHighlight } from '../extensions/CodeBlockSyntaxHighlight';
Expand Down Expand Up @@ -30,6 +31,9 @@ export function useEditor() {
Image,
CustomLink, // Use our custom Link extension
Math,
TextAlign.configure({
types: ['heading', 'paragraph', 'image'],
}),
],
content: content || '<p></p>',
editorProps: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export function useToolbarActions(emit) {
mathFormula$,
codeBlock$,
clipboardAccessFailed$,
alignLeft$,
alignRight$,
} = getTipTapEditorStrings();

// Action handlers
Expand Down Expand Up @@ -181,6 +183,17 @@ export function useToolbarActions(emit) {
}
};

const handleToggleAlign = () => {
if (editor?.value) {
const isRightAligned = editor.value.isActive({ textAlign: 'right' });
if (isRightAligned) {
editor.value.chain().focus().setTextAlign('left').run();
} else {
editor.value.chain().focus().setTextAlign('right').run();
}
}
};

const handleBulletList = () => {
if (editor?.value) {
editor.value.chain().focus().toggleBulletList().run();
Expand Down Expand Up @@ -418,6 +431,20 @@ export function useToolbarActions(emit) {
handler: handleMinimize,
};

const alignAction = computed(() => {
const isRightAligned = editor?.value?.isActive({ textAlign: 'right' }) || false;
return {
name: 'toggleAlign',
title: isRightAligned ? alignLeft$() : alignRight$(),
icon: isRightAligned
? require('../../assets/icon-alignLeft.svg')
: require('../../assets/icon-alignRight.svg'),
handler: handleToggleAlign,
isActive: false,
isAvailable: !isMarkActive('codeBlock'),
};
});

return {
// Individual handlers
handleUndo,
Expand All @@ -429,6 +456,7 @@ export function useToolbarActions(emit) {
handleCopy,
handlePaste,
handlePasteNoFormat,
handleToggleAlign,
handleBulletList,
handleNumberList,
handleSubscript,
Expand All @@ -444,6 +472,7 @@ export function useToolbarActions(emit) {
// Action arrays
historyActions,
textActions,
alignAction,
listActions,
scriptActions,
insertTools,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ export const Image = Node.create({
alt: { default: null },
width: { default: null },
height: { default: null },
textAlign: {
default: 'left',
parseHTML: element => {
const align = element.style.textAlign || element.getAttribute('data-text-align');
return align || 'left';
},
renderHTML: attributes => {
if (!attributes.textAlign || attributes.textAlign === 'left') {
return {};
}
return { 'data-text-align': attributes.textAlign };
},
},
};
},

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"@tiptap/extension-link": "^3.13.0",
"@tiptap/extension-subscript": "^3.13.0",
"@tiptap/extension-superscript": "^3.13.0",
"@tiptap/extension-text-align": "^3.18.0",
"@tiptap/starter-kit": "^3.13.0",
"@tiptap/vue-2": "^3.13.0",
"ajv": "^8.12.0",
Expand Down
12 changes: 12 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.