From b0ae6f09af766d1971b02e80592003461813a4d5 Mon Sep 17 00:00:00 2001 From: Steffen Becker Date: Wed, 12 Aug 2026 01:40:07 +0200 Subject: [PATCH] feat: the ribbon's Insert tab Page break, table, picture, text box, link, bookmark, cross-reference, header, footer, page number, date, symbol and equation. The page break had a key and no button; the rest moved up from the secondary toolbar. The ribbon mounts its own link, bookmark, cross-reference and formula dialogs, so the classic path keeps the ones it has and its re-fire shim untouched. Only one chrome is mounted, so the two sets never coexist. --- src/App.svelte | 6 + src/lib/components/ribbon/Ribbon.svelte | 19 + src/lib/components/ribbon/icons.ts | 9 + .../components/ribbon/tabs/InsertTab.svelte | 328 ++++++++++++++++++ src/lib/i18n/locales/de.ts | 20 ++ src/lib/i18n/locales/en.ts | 20 ++ 6 files changed, 402 insertions(+) create mode 100644 src/lib/components/ribbon/tabs/InsertTab.svelte diff --git a/src/App.svelte b/src/App.svelte index f0e0d27..cfeba9c 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -832,7 +832,13 @@ bind:chromeMode bind:documentName bind:showFormattingMarks + {pageMargins} + {pageOrientation} + {pageFormat} + {hfActive} onManageStyles={openStyleManager} + onManageTableStyles={() => openStyleManager('table')} + onEditZone={(zone) => (hfActive = zone)} onFind={openFind} {namePlaceholder} {themeMode} diff --git a/src/lib/components/ribbon/Ribbon.svelte b/src/lib/components/ribbon/Ribbon.svelte index 883577d..5df2e92 100644 --- a/src/lib/components/ribbon/Ribbon.svelte +++ b/src/lib/components/ribbon/Ribbon.svelte @@ -4,6 +4,7 @@ import RibbonMenu from './RibbonMenu.svelte'; import HistoryButton from '../HistoryButton.svelte'; import HomeTab from './tabs/HomeTab.svelte'; + import InsertTab from './tabs/InsertTab.svelte'; import UiLanguagePicker from '../UiLanguagePicker.svelte'; import { clickOutside, isMenuOpen, toggleMenu, closeMenu } from './menu.svelte'; import { t } from '../../i18n/i18n.svelte'; @@ -11,6 +12,10 @@ import { shortcutHint } from '../../editor/shortcuts'; import type { ChromeMode, ThemeMode } from '../../storage/theme'; import type { StyleFamily } from '../../styles/styleSheet'; + import type { PageMargins } from '../../storage/pageMargins'; + import type { Orientation } from '../../storage/pageOrientation'; + import type { PageFormat } from '../../storage/pageFormat'; + import type { HfZone } from '../../storage/headerFooter'; let { editor, @@ -18,7 +23,13 @@ chromeMode = $bindable('ribbon'), documentName = $bindable(''), showFormattingMarks = $bindable(false), + pageMargins, + pageOrientation, + pageFormat, + hfActive = null, onManageStyles, + onManageTableStyles, + onEditZone, onFind, namePlaceholder = '', themeMode = 'auto', @@ -32,7 +43,13 @@ chromeMode?: ChromeMode; documentName?: string; showFormattingMarks?: boolean; + pageMargins: PageMargins; + pageOrientation: Orientation; + pageFormat: PageFormat; + hfActive?: HfZone | null; onManageStyles?: (family: StyleFamily) => void; + onManageTableStyles?: (family: StyleFamily) => void; + onEditZone?: (zone: HfZone) => void; onFind?: (mode: 'find' | 'replace') => void; namePlaceholder?: string; themeMode?: ThemeMode; @@ -185,6 +202,8 @@
{#if tab === 'home'} + {:else if tab === 'insert'} + {/if}
diff --git a/src/lib/components/ribbon/icons.ts b/src/lib/components/ribbon/icons.ts index a2e77b0..bddbbf4 100644 --- a/src/lib/components/ribbon/icons.ts +++ b/src/lib/components/ribbon/icons.ts @@ -57,6 +57,15 @@ export const STROKED = { find: ['M7.25 12.5a5.25 5.25 0 1 0 0-10.5 5.25 5.25 0 0 0 0 10.5z', 'M11.2 11.2 14 14'], replace: ['M2 4.5h6.5M2 4.5 4 2.5M2 4.5l2 2', 'M14 11.5H7.5M14 11.5l-2-2M14 11.5l-2 2'], + image: ['M2 3.25h12v9.5H2z', 'M2 10.5 5.75 7l3 2.75L11 7.5l3 3', 'M10.6 6.4a1.1 1.1 0 1 0 0-2.2 1.1 1.1 0 0 0 0 2.2z'], + textBox: ['M1.75 4h12.5v8H1.75z', 'M5 6.5h6M5 9h4'], + link: ['M6.6 9.4 9.4 6.6', 'M7.4 4.4 9 2.8a2.7 2.7 0 0 1 3.8 3.8l-1.6 1.6', 'M8.6 11.6 7 13.2a2.7 2.7 0 0 1-3.8-3.8l1.6-1.6'], + bookmark: ['M4 2.25h8v11.5L8 10.5l-4 3.25z'], + crossRef: ['M2.5 3.5h6M2.5 6.5h4M2.5 9.5h5', 'M8.5 12.5h5M11 10l2.5 2.5L11 15'], + header: ['M2 2.5h12v3H2z', 'M2 8h12M2 11h8'], + footer: ['M2 10.5h12v3H2z', 'M2 5h12M2 8h8'], + pageNumber: ['M3.25 1.75h9.5v12.5h-9.5z', 'M6.75 10.5h2.5', 'M8 5.5v5'], + formula: ['M9 3.5h4', 'M9.5 8h3', 'M2.5 13.5c1.6 0 2-.9 2.4-2.4L7.2 3.4C7.5 2.3 8 2 8.8 2', 'M2.5 6.5h4'], pageBreak: ['M2 4.5h12M2 11.5h12', 'M8 6.5v3', 'M6.4 8.2 8 9.8l1.6-1.6'], } as const; diff --git a/src/lib/components/ribbon/tabs/InsertTab.svelte b/src/lib/components/ribbon/tabs/InsertTab.svelte new file mode 100644 index 0000000..6d9354d --- /dev/null +++ b/src/lib/components/ribbon/tabs/InsertTab.svelte @@ -0,0 +1,328 @@ + + + + editor?.chain().focus().insertPageBreak().run()} + /> + + +
+ + +
+ editor?.chain().focus().setTextSelection(range).insertTable({ rows, cols, withHeaderRow: false }).run()} + onManageStyles={() => onManageTableStyles?.('table')} + /> + {t().ribbon.table} +
+
+ +
+ + + imageInput?.click()} /> + editor?.chain().focus().insertTextBox().run()} + /> + + +
+ + + + + +
+ + + onEditZone?.('header')} /> + onEditZone?.('footer')} /> +
+ toggleMenu('pageField')} onCaret={() => toggleMenu('pageField')} /> + {#if isMenuOpen('pageField')} + + {/if} +
+
+ +
+ + +
+ editor?.chain().focus().setTextSelection(range).insertDateTimeField(opts).run()} + /> + {t().ribbon.dateTime} +
+
+ +
+ + +
+ editor?.chain().focus().setTextSelection(range).insertContent(char).run()} + /> + {t().ribbon.symbol} +
+ +
+ + + + + + diff --git a/src/lib/i18n/locales/de.ts b/src/lib/i18n/locales/de.ts index 03ed93d..d6c4031 100644 --- a/src/lib/i18n/locales/de.ts +++ b/src/lib/i18n/locales/de.ts @@ -463,6 +463,13 @@ const de: Messages = { clipboard: 'Zwischenablage', font: 'Schriftart', paragraph: 'Absatz', + pages: 'Seiten', + tables: 'Tabellen', + illustrations: 'Illustrationen', + links: 'Links', + headerFooter: 'Kopf- und Fußzeile', + text: 'Text', + symbols: 'Symbole', editing: 'Bearbeiten', }, case: { @@ -480,6 +487,19 @@ const de: Messages = { dashed: 'Gestrichelt', wavy: 'Wellenlinie', }, + pageBreak: 'Seitenumbruch', + picture: 'Bild', + textBox: 'Textfeld', + crossRef: 'Querverweis', + pageNumber: 'Seitenzahl', + equation: 'Formel', + header: 'Kopfzeile', + footer: 'Fußzeile', + link: 'Link', + bookmark: 'Textmarke', + table: 'Tabelle', + dateTime: 'Datum & Uhrzeit', + symbol: 'Symbol', chrome: { title: 'Symbolleisten-Stil', ribbon: 'Menüband', diff --git a/src/lib/i18n/locales/en.ts b/src/lib/i18n/locales/en.ts index a6fe331..46d793a 100644 --- a/src/lib/i18n/locales/en.ts +++ b/src/lib/i18n/locales/en.ts @@ -467,6 +467,13 @@ const en = { clipboard: 'Clipboard', font: 'Font', paragraph: 'Paragraph', + pages: 'Pages', + tables: 'Tables', + illustrations: 'Illustrations', + links: 'Links', + headerFooter: 'Header & Footer', + text: 'Text', + symbols: 'Symbols', editing: 'Editing', }, case: { @@ -484,6 +491,19 @@ const en = { dashed: 'Dashed', wavy: 'Wavy', }, + pageBreak: 'Page break', + picture: 'Picture', + textBox: 'Text box', + crossRef: 'Cross-reference', + pageNumber: 'Page number', + equation: 'Equation', + header: 'Header', + footer: 'Footer', + link: 'Link', + bookmark: 'Bookmark', + table: 'Table', + dateTime: 'Date & time', + symbol: 'Symbol', chrome: { title: 'Toolbar style', ribbon: 'Ribbon',