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.
This commit is contained in:
1 parent
ac93ba8651
commit
b0ae6f09af
6 files changed
+402
No files matched your search
@@ -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}
|
||||
|
||||
@@ -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<ChromeMode>('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 @@
|
||||
<div class="ribbon-body">
|
||||
{#if tab === 'home'}
|
||||
<HomeTab {editor} {tick} bind:showFormattingMarks {onManageStyles} {onFind} />
|
||||
{:else if tab === 'insert'}
|
||||
<InsertTab {editor} {tick} {hfActive} {pageMargins} {pageOrientation} {pageFormat} {onEditZone} {onManageTableStyles} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
<script lang="ts">
|
||||
import type { Editor } from '@tiptap/core';
|
||||
import RibbonGroup from '../RibbonGroup.svelte';
|
||||
import RibbonButton from '../RibbonButton.svelte';
|
||||
import TablePicker from '../../TablePicker.svelte';
|
||||
import SpecialCharPicker from '../../SpecialCharPicker.svelte';
|
||||
import DateTimePicker from '../../DateTimePicker.svelte';
|
||||
import LinkDialog from '../../LinkDialog.svelte';
|
||||
import BookmarkDialog from '../../BookmarkDialog.svelte';
|
||||
import CrossRefDialog from '../../CrossRefDialog.svelte';
|
||||
import FormulaDialog from '../../FormulaDialog.svelte';
|
||||
import { anchored, clickOutside, isMenuOpen, toggleMenu, closeMenu } from '../menu.svelte';
|
||||
import { OPEN_LINK_DIALOG_EVENT } from '../../../editor/extensions/link';
|
||||
import { OPEN_BOOKMARK_DIALOG_EVENT, bookmarkNames, findBookmark } from '../../../editor/extensions/bookmark';
|
||||
import { OPEN_CROSS_REF_DIALOG_EVENT } from '../../../editor/extensions/crossReference';
|
||||
import { EDIT_FORMULA_EVENT } from '../../../editor/extensions/formula';
|
||||
import { pageDimsCm, type PageFormat } from '../../../storage/pageFormat';
|
||||
import { cmToPx, type PageMargins } from '../../../storage/pageMargins';
|
||||
import type { Orientation } from '../../../storage/pageOrientation';
|
||||
import type { HfZone } from '../../../storage/headerFooter';
|
||||
import type { StyleFamily } from '../../../styles/styleSheet';
|
||||
import { t } from '../../../i18n/i18n.svelte';
|
||||
import { shortcutHint } from '../../../editor/shortcuts';
|
||||
|
||||
let {
|
||||
editor, tick, hfActive = null, pageMargins, pageOrientation, pageFormat,
|
||||
onEditZone, onManageTableStyles,
|
||||
}: {
|
||||
editor: Editor | null;
|
||||
tick: number;
|
||||
hfActive?: HfZone | null;
|
||||
pageMargins: PageMargins;
|
||||
pageOrientation: Orientation;
|
||||
pageFormat: PageFormat;
|
||||
onEditZone?: (zone: HfZone) => void;
|
||||
onManageTableStyles?: (family: StyleFamily) => void;
|
||||
} = $props();
|
||||
|
||||
let hasSelection = $derived(tick >= 0 && !!editor && !editor.state.selection.empty);
|
||||
let isLink = $derived(tick >= 0 && !!editor?.isActive('link'));
|
||||
let bmNames = $derived(tick >= 0 && editor && !hfActive ? bookmarkNames(editor.state.doc) : []);
|
||||
|
||||
let tableOpen = $state(false);
|
||||
let charOpen = $state(false);
|
||||
let dateOpen = $state(false);
|
||||
|
||||
// The page text box in px, so an inserted image never starts wider or taller
|
||||
// than one page (the same content-width math the export does).
|
||||
function contentBoxPx(): { maxW: number; maxH: number } {
|
||||
const { w, h } = pageDimsCm(pageFormat, pageOrientation);
|
||||
return {
|
||||
maxW: Math.round(cmToPx(w - pageMargins.left - pageMargins.right)),
|
||||
maxH: Math.round(cmToPx(h - pageMargins.top - pageMargins.bottom)),
|
||||
};
|
||||
}
|
||||
|
||||
let imageInput = $state<HTMLInputElement | null>(null);
|
||||
|
||||
function onImageFile(e: Event) {
|
||||
const input = e.target as HTMLInputElement;
|
||||
const file = input.files?.[0];
|
||||
input.value = ''; // so the same file can be picked again
|
||||
if (!file || !editor) return;
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
const src = reader.result as string;
|
||||
const probe = document.createElement('img');
|
||||
probe.onload = () => {
|
||||
let w = probe.naturalWidth || 1;
|
||||
let h = probe.naturalHeight || 1;
|
||||
const { maxW, maxH } = contentBoxPx();
|
||||
if (w > maxW) { h = (h * maxW) / w; w = maxW; }
|
||||
if (h > maxH) { w = (w * maxH) / h; h = maxH; }
|
||||
editor!.chain().focus().setImage({ src, alt: file.name, width: Math.round(w), height: Math.round(h) }).run();
|
||||
};
|
||||
probe.src = src;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
// --- Link ---
|
||||
let linkOpen = $state(false);
|
||||
let linkUrl = $state('');
|
||||
|
||||
function openLink() {
|
||||
if (!editor || hfActive) return; // body-only; the HF schema has no link mark
|
||||
linkUrl = (editor.getAttributes('link').href as string) ?? '';
|
||||
linkOpen = true;
|
||||
}
|
||||
|
||||
// A bare host or e-mail gets a scheme, as in Word and LibreOffice.
|
||||
function normalizeUrl(raw: string): string {
|
||||
const s = raw.trim();
|
||||
if (!s) return '';
|
||||
if (/^(https?:|mailto:|tel:|ftp:|#|\/)/i.test(s)) return s;
|
||||
if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s)) return `mailto:${s}`;
|
||||
return `https://${s}`;
|
||||
}
|
||||
|
||||
function applyLink(raw: string) {
|
||||
linkOpen = false;
|
||||
if (!editor) return;
|
||||
const href = normalizeUrl(raw);
|
||||
if (!href) return;
|
||||
const { empty } = editor.state.selection;
|
||||
// With nothing selected the URL becomes its own link text.
|
||||
if (empty) editor.chain().focus().insertContent({ type: 'text', text: href, marks: [{ type: 'link', attrs: { href } }] }).run();
|
||||
else editor.chain().focus().extendMarkRange('link').setLink({ href }).run();
|
||||
}
|
||||
|
||||
// --- Bookmarks and cross-references ---
|
||||
let bookmarkOpen = $state(false);
|
||||
let crossRefOpen = $state(false);
|
||||
|
||||
function openBookmark() {
|
||||
if (!editor || hfActive || !hasSelection) return;
|
||||
crossRefOpen = false;
|
||||
bookmarkOpen = true;
|
||||
}
|
||||
|
||||
function openCrossRef() {
|
||||
if (!editor || hfActive || !bmNames.length) return;
|
||||
bookmarkOpen = false;
|
||||
crossRefOpen = true;
|
||||
}
|
||||
|
||||
function goToBookmark(name: string) {
|
||||
const found = editor && findBookmark(editor.state.doc, name);
|
||||
if (!editor || !found) return;
|
||||
bookmarkOpen = false;
|
||||
editor.chain().focus().setTextSelection({ from: found.from, to: found.to }).scrollIntoView().run();
|
||||
}
|
||||
|
||||
// --- Formula ---
|
||||
let formulaOpen = $state(false);
|
||||
let formulaLatex = $state('');
|
||||
let formulaDisplay = $state(false);
|
||||
let formulaPos = $state<number | null>(null);
|
||||
|
||||
function openFormula() {
|
||||
formulaPos = null;
|
||||
formulaLatex = '';
|
||||
formulaDisplay = false;
|
||||
formulaOpen = true;
|
||||
}
|
||||
|
||||
function applyFormula(latex: string, display: boolean) {
|
||||
if (!editor) return;
|
||||
if (formulaPos != null) editor.chain().focus().updateFormula(formulaPos, { latex, display }).run();
|
||||
else editor.chain().focus().insertFormula({ latex, display }).run();
|
||||
formulaPos = null;
|
||||
}
|
||||
|
||||
// Ctrl+K, the context menu and a double-click on a formula all arrive as events.
|
||||
$effect(() => {
|
||||
const onLink = () => openLink();
|
||||
const onBm = () => openBookmark();
|
||||
const onXr = () => openCrossRef();
|
||||
const onFormula = (e: Event) => {
|
||||
const d = (e as CustomEvent<{ pos: number; latex: string; display: boolean }>).detail;
|
||||
if (!d) return;
|
||||
formulaPos = d.pos;
|
||||
formulaLatex = d.latex;
|
||||
formulaDisplay = d.display;
|
||||
formulaOpen = true;
|
||||
};
|
||||
window.addEventListener(OPEN_LINK_DIALOG_EVENT, onLink);
|
||||
window.addEventListener(OPEN_BOOKMARK_DIALOG_EVENT, onBm);
|
||||
window.addEventListener(OPEN_CROSS_REF_DIALOG_EVENT, onXr);
|
||||
window.addEventListener(EDIT_FORMULA_EVENT, onFormula);
|
||||
return () => {
|
||||
window.removeEventListener(OPEN_LINK_DIALOG_EVENT, onLink);
|
||||
window.removeEventListener(OPEN_BOOKMARK_DIALOG_EVENT, onBm);
|
||||
window.removeEventListener(OPEN_CROSS_REF_DIALOG_EVENT, onXr);
|
||||
window.removeEventListener(EDIT_FORMULA_EVENT, onFormula);
|
||||
};
|
||||
});
|
||||
|
||||
// A page field only means anything inside a zone, so open the footer first.
|
||||
function insertPageField(type: 'pageNumber' | 'pageCount') {
|
||||
closeMenu();
|
||||
if (!hfActive) return void onEditZone?.('footer');
|
||||
editor?.chain().focus().insertContent({ type }).run();
|
||||
}
|
||||
</script>
|
||||
|
||||
<RibbonGroup label={t().ribbon.groups.pages}>
|
||||
<RibbonButton
|
||||
variant="big"
|
||||
icon="pageBreak"
|
||||
label={t().ribbon.pageBreak}
|
||||
title={`${t().ribbon.pageBreak} (${shortcutHint('pageBreak')})`}
|
||||
disabled={!editor || !!hfActive}
|
||||
onclick={() => editor?.chain().focus().insertPageBreak().run()}
|
||||
/>
|
||||
</RibbonGroup>
|
||||
|
||||
<div class="ribbon-sep"></div>
|
||||
|
||||
<RibbonGroup label={t().ribbon.groups.tables}>
|
||||
<div class="rb-captioned">
|
||||
<TablePicker
|
||||
{editor}
|
||||
bind:open={tableOpen}
|
||||
onInsert={(rows, cols, range) => editor?.chain().focus().setTextSelection(range).insertTable({ rows, cols, withHeaderRow: false }).run()}
|
||||
onManageStyles={() => onManageTableStyles?.('table')}
|
||||
/>
|
||||
<span class="rb-caption">{t().ribbon.table}</span>
|
||||
</div>
|
||||
</RibbonGroup>
|
||||
|
||||
<div class="ribbon-sep"></div>
|
||||
|
||||
<RibbonGroup label={t().ribbon.groups.illustrations}>
|
||||
<RibbonButton variant="big" icon="image" label={t().ribbon.picture} title={t().toolbarExpanded.insertImage} disabled={!editor} onclick={() => imageInput?.click()} />
|
||||
<RibbonButton
|
||||
variant="big"
|
||||
icon="textBox"
|
||||
label={t().ribbon.textBox}
|
||||
title={hfActive ? t().toolbarExpanded.textBoxNotInHf : t().toolbarExpanded.insertTextBox}
|
||||
disabled={!editor || !!hfActive}
|
||||
onclick={() => editor?.chain().focus().insertTextBox().run()}
|
||||
/>
|
||||
</RibbonGroup>
|
||||
|
||||
<div class="ribbon-sep"></div>
|
||||
|
||||
<RibbonGroup label={t().ribbon.groups.links}>
|
||||
<div class="rb-col link-anchor">
|
||||
<RibbonButton variant="small" icon="link" label={t().ribbon.link} title={`${isLink ? t().link.dialogLabel : t().ribbon.link} (${shortcutHint('link')})`} disabled={!editor || !!hfActive} onclick={openLink} />
|
||||
<RibbonButton variant="small" icon="bookmark" label={t().ribbon.bookmark} title={hfActive ? t().toolbarExpanded.bookmarkNotInHf : hasSelection ? t().toolbarExpanded.insertBookmark : t().toolbarExpanded.bookmarkNeedsSelection} disabled={!editor || !!hfActive || !hasSelection} onclick={openBookmark} />
|
||||
<RibbonButton variant="small" icon="crossRef" label={t().ribbon.crossRef} title={hfActive ? t().toolbarExpanded.bookmarkNotInHf : bmNames.length ? t().toolbarExpanded.insertCrossRef : t().toolbarExpanded.crossRefNeedsBookmark} disabled={!editor || !!hfActive || !bmNames.length} onclick={openCrossRef} />
|
||||
<LinkDialog open={linkOpen} initialUrl={linkUrl} canRemove={isLink} onApply={applyLink} onRemove={() => { linkOpen = false; editor?.chain().focus().extendMarkRange('link').unsetLink().run(); }} onClose={() => (linkOpen = false)} />
|
||||
<BookmarkDialog open={bookmarkOpen} names={bmNames} onApply={(n) => { bookmarkOpen = false; editor?.chain().focus().setBookmark(n).run(); }} onRemove={(n) => editor?.chain().focus().removeBookmark(n).run()} onGoTo={goToBookmark} onClose={() => (bookmarkOpen = false)} />
|
||||
<CrossRefDialog open={crossRefOpen} names={bmNames} onInsert={(n, f) => { crossRefOpen = false; editor?.chain().focus().insertCrossRef({ name: n, format: f }).run(); }} onClose={() => (crossRefOpen = false)} />
|
||||
</div>
|
||||
</RibbonGroup>
|
||||
|
||||
<div class="ribbon-sep"></div>
|
||||
|
||||
<RibbonGroup label={t().ribbon.groups.headerFooter}>
|
||||
<RibbonButton variant="big" icon="header" label={t().ribbon.header} title={t().toolbarExpanded.editHeader} disabled={!editor} onclick={() => onEditZone?.('header')} />
|
||||
<RibbonButton variant="big" icon="footer" label={t().ribbon.footer} title={t().toolbarExpanded.editFooter} disabled={!editor} onclick={() => onEditZone?.('footer')} />
|
||||
<div class="rb-menu-wrap" use:clickOutside={'pageField'}>
|
||||
<RibbonButton variant="big" icon="pageNumber" label={t().ribbon.pageNumber} title={t().ribbon.pageNumber} caret caretActive={isMenuOpen('pageField')} onclick={() => toggleMenu('pageField')} onCaret={() => toggleMenu('pageField')} />
|
||||
{#if isMenuOpen('pageField')}
|
||||
<div class="ribbon-menu" use:anchored role="menu">
|
||||
<button onclick={() => insertPageField('pageNumber')}>{t().hf.pageNumber}</button>
|
||||
<button onclick={() => insertPageField('pageCount')}>{t().hf.pageCount}</button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</RibbonGroup>
|
||||
|
||||
<div class="ribbon-sep"></div>
|
||||
|
||||
<RibbonGroup label={t().ribbon.groups.text}>
|
||||
<div class="rb-captioned">
|
||||
<DateTimePicker
|
||||
bind:open={dateOpen}
|
||||
{editor}
|
||||
onInsert={(opts, range) => editor?.chain().focus().setTextSelection(range).insertDateTimeField(opts).run()}
|
||||
/>
|
||||
<span class="rb-caption">{t().ribbon.dateTime}</span>
|
||||
</div>
|
||||
</RibbonGroup>
|
||||
|
||||
<div class="ribbon-sep"></div>
|
||||
|
||||
<RibbonGroup label={t().ribbon.groups.symbols}>
|
||||
<div class="rb-captioned">
|
||||
<SpecialCharPicker
|
||||
bind:open={charOpen}
|
||||
{editor}
|
||||
onInsert={(char, range) => editor?.chain().focus().setTextSelection(range).insertContent(char).run()}
|
||||
/>
|
||||
<span class="rb-caption">{t().ribbon.symbol}</span>
|
||||
</div>
|
||||
<RibbonButton variant="big" icon="formula" label={t().ribbon.equation} title={t().formula.insert} disabled={!editor} onclick={openFormula} />
|
||||
</RibbonGroup>
|
||||
|
||||
<input
|
||||
bind:this={imageInput}
|
||||
type="file"
|
||||
accept="image/*"
|
||||
class="file-input"
|
||||
onchange={onImageFile}
|
||||
/>
|
||||
|
||||
<FormulaDialog bind:open={formulaOpen} initialLatex={formulaLatex} initialDisplay={formulaDisplay} onApply={applyFormula} />
|
||||
|
||||
<style>
|
||||
.rb-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 2px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.link-anchor { position: relative; }
|
||||
|
||||
/* A reused picker draws its own compact trigger, so the caption is what makes
|
||||
it read like the labelled buttons beside it. */
|
||||
.rb-captioned {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 4px 7px 6px;
|
||||
}
|
||||
|
||||
.rb-caption {
|
||||
font-family: var(--w-font);
|
||||
font-size: 12px;
|
||||
color: var(--w-text);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.rb-menu-wrap { position: relative; }
|
||||
|
||||
.file-input {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in new issue
Block a user