diff --git a/apps/docs/docs/widgets/notebook/index.mdx b/apps/docs/docs/widgets/notebook/index.mdx index 5728e0113..393137ed2 100644 --- a/apps/docs/docs/widgets/notebook/index.mdx +++ b/apps/docs/docs/widgets/notebook/index.mdx @@ -1,29 +1,25 @@ --- -title: 'Notebook' -description: 'A simple notebook widget that supports markdown.' +title: "Notebook" +description: "A simple notebook widget that supports markdown." hide_title: true --- -import { AddingWidget } from '@site/src/components/widgets/adding'; -import { WidgetConfig } from '@site/src/components/widgets/configuration'; -import { WidgetHeader } from '@site/src/components/widgets/header'; -import { notebookWidget } from '.'; +import { AddingWidget } from "@site/src/components/widgets/adding"; +import { WidgetConfig } from "@site/src/components/widgets/configuration"; +import { WidgetHeader } from "@site/src/components/widgets/header"; +import { notebookWidget } from "."; + - - -The notebook widget focuses on usability and is designed to be as simple as possible to bring a familiar editing experience to regular users. +The notebook widget focuses on usability and is designed to be as simple as possible to bring a familiar editing experience to regular users. It is based on Tiptap.dev and supports most of its features. ### Screenshots -import editOff from './img/normal.png'; -import editOn from './img/edit.png'; +import editOff from "./img/normal.png"; +import editOn from "./img/edit.png"; -
+
notebook edit-off notebook edit-on
@@ -33,24 +29,27 @@ import editOn from './img/edit.png'; ### Configuration + ### Editing + When the permissions of the user allows it, you can enter the editing of the text by clicking the following button in the top right. ![](./img/notebook-enter-editing.webp) - You can then decide to save your changes or cancel them to exit editing, using the buttons placed in the same location. ![](./img/notebook-exit-editing.webp) ### Notebook toolbar functions -The notebook offers a variaty of functions to edit the text and more. + +The notebook offers a variety of functions to edit the text and more. ![](./img/notebook-toolbar.webp) #### Common text formatting + | Function | Description | | ---------------------- | ------------------------------------------------------------------- | | Bold | Makes the selected text bold | @@ -62,35 +61,51 @@ The notebook offers a variaty of functions to edit the text and more. | Clear formatting | Erases any of the preceding function's effects on the selected text | #### Heading + Choose a heading size for the line, making the text bigger. Working like titles and sub-titles. -#### Text Alignement -Select the alignement on the line. Left, center or right. +#### Text Alignment + +Select the alignment on the line. Left, center or right. + +#### Text direction + +Set the current paragraph or heading to left-to-right or right-to-left. This is useful when writing right-to-left text while Homarr is using a left-to-right language, or vice versa. #### Misc functions + ##### Blockquote + Puts the current line in a quoting block. ##### Horizontal line + Adds a line that goes from the far right to the far left as a separator. #### Lists + ##### Bullet lists + Simple list with a dot preceding each element. ##### Ordered lists + List with numbers preceding each element. ##### Check lists + List with a checkbox on each element. ##### Indentation changes + ![](./img/notebook-toolbar-lists.webp) When you are currently in a list of any sort, the last 2 buttons will appear and will allow you to change the indentation of the current list item. #### Insert functions + ##### Link controls + The first buttons is to insert a link, or edit an existing link. The link will be applied on the selected text. Pasting a link directly into the text will automatically put the link anchor on it too. @@ -102,16 +117,20 @@ The second button will remove the link while leaving the text intact. This is the modal for the link, The little button in the textbox can be clicked to make the link open in a new tab. ##### Image controls + ![](./img/notebook-image-modal.webp) ##### Source + You can use a normal link to an image or you can also use locally stored images. ##### Width + The aspect ratio will always be respected, so only the width field is necessary. You can provide a value in a plain number or you can also use percents to have your image size dynamically change on different screens. #### Table + This last control allows you to add a table, for which you can determine the number of columns and row before inserting it. ![](./img/notebook-table-modal.webp) @@ -119,6 +138,7 @@ This last control allows you to add a table, for which you can determine the num Clicking that button while in a table will delete it. ##### Table controls + ![](./img/notebook-toolbar-table.webp) While in a table, further controls will appear to help edit the table. @@ -134,4 +154,4 @@ All the following ones are for editing the wize of the table: - Delete Column - Add row on top - Add row below -- Delete Row \ No newline at end of file +- Delete Row diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json index 7a2c27b24..ad97ab109 100644 --- a/packages/translation/src/lang/en.json +++ b/packages/translation/src/lang/en.json @@ -1956,6 +1956,8 @@ "clear": "Clear formatting", "heading": "Heading {level}", "align": "Align text: {position}", + "directionLtr": "Set text direction left to right", + "directionRtl": "Set text direction right to left", "blockquote": "Blockquote", "horizontalLine": "Horizontal line", "bulletList": "Bullet list", diff --git a/packages/widgets/src/notebook/notebook.tsx b/packages/widgets/src/notebook/notebook.tsx index 229b3730a..9fdd692fb 100644 --- a/packages/widgets/src/notebook/notebook.tsx +++ b/packages/widgets/src/notebook/notebook.tsx @@ -39,6 +39,8 @@ import { IconRowRemove, IconTableOff, IconTablePlus, + IconTextDirectionLtr, + IconTextDirectionRtl, IconX, } from "@tabler/icons-react"; import { Color } from "@tiptap/extension-color"; @@ -66,6 +68,7 @@ import { useI18n, useScopedI18n } from "@homarr/translation/client"; import type { TablerIcon } from "@homarr/ui"; import type { WidgetComponentProps } from "../definition"; +import { NotebookTextDirection, setTextDirection } from "./text-direction"; import "@mantine/tiptap/styles.css"; import "./notebook.css"; @@ -171,6 +174,7 @@ export function Notebook({ options, setOptions, isEditMode, boardId, itemId }: W }), TaskList.configure({ itemTypeName: "taskItem" }), TextAlign.configure({ types: ["heading", "paragraph"] }), + NotebookTextDirection, TextStyle, ], shouldRerenderOnTransaction: true, @@ -347,6 +351,22 @@ export function Notebook({ options, setOptions, isEditMode, boardId, itemId }: W position: t("widget.notebook.align.right"), })} /> + editor && setTextDirection(editor, "ltr").run()} + > + + + editor && setTextDirection(editor, "rtl").run()} + > + + diff --git a/packages/widgets/src/notebook/text-direction.spec.ts b/packages/widgets/src/notebook/text-direction.spec.ts new file mode 100644 index 000000000..62b0313df --- /dev/null +++ b/packages/widgets/src/notebook/text-direction.spec.ts @@ -0,0 +1,34 @@ +import { Editor } from "@tiptap/react"; +import { StarterKit } from "@tiptap/starter-kit"; +import { describe, expect, it } from "vitest"; + +import { NotebookTextDirection, setTextDirection } from "./text-direction"; + +describe("notebook text direction", () => { + it("persists right-to-left direction in the notebook HTML", () => { + const editor = new Editor({ + content: "

יש לי 16GB

", + extensions: [StarterKit, NotebookTextDirection], + }); + + setTextDirection(editor, "rtl").run(); + + expect(editor.getHTML()).toBe('

יש לי 16GB

'); + editor.destroy(); + }); + + it("reads and changes an existing direction attribute", () => { + const editor = new Editor({ + content: '

Heading

', + extensions: [StarterKit, NotebookTextDirection], + }); + + expect(editor.getHTML()).toBe('

Heading

'); + + editor.commands.setTextSelection(1); + setTextDirection(editor, "ltr").run(); + + expect(editor.getHTML()).toContain('

Heading

'); + editor.destroy(); + }); +}); diff --git a/packages/widgets/src/notebook/text-direction.ts b/packages/widgets/src/notebook/text-direction.ts new file mode 100644 index 000000000..7ab9ea022 --- /dev/null +++ b/packages/widgets/src/notebook/text-direction.ts @@ -0,0 +1,28 @@ +import { Extension } from "@tiptap/react"; +import type { Editor } from "@tiptap/react"; + +export type TextDirection = "ltr" | "rtl"; + +export const NotebookTextDirection = Extension.create({ + name: "notebookTextDirection", + + addGlobalAttributes() { + return [ + { + types: ["heading", "paragraph"], + attributes: { + dir: { + default: null, + parseHTML: (element) => element.getAttribute("dir"), + renderHTML: ({ dir }: { dir?: TextDirection }) => (dir ? { dir } : {}), + }, + }, + }, + ]; + }, +}); + +export function setTextDirection(editor: Editor, direction: TextDirection) { + const nodeType = editor.isActive("heading") ? "heading" : "paragraph"; + return editor.chain().focus().updateAttributes(nodeType, { dir: direction }); +}