diff --git a/docs/showcase/book-spread.png b/docs/showcase/book-spread.png index ac6427f..72a3c77 100644 Binary files a/docs/showcase/book-spread.png and b/docs/showcase/book-spread.png differ diff --git a/docs/showcase/book.docx b/docs/showcase/book.docx index 329d658..2fa1eba 100644 Binary files a/docs/showcase/book.docx and b/docs/showcase/book.docx differ diff --git a/docs/showcase/book.odt b/docs/showcase/book.odt index 1241a55..c8b5110 100644 Binary files a/docs/showcase/book.odt and b/docs/showcase/book.odt differ diff --git a/docs/showcase/newsletter-tables.png b/docs/showcase/newsletter-tables.png index 8af5626..95dea8d 100644 Binary files a/docs/showcase/newsletter-tables.png and b/docs/showcase/newsletter-tables.png differ diff --git a/docs/showcase/newsletter.docx b/docs/showcase/newsletter.docx index aee01c1..df77edd 100644 Binary files a/docs/showcase/newsletter.docx and b/docs/showcase/newsletter.docx differ diff --git a/docs/showcase/newsletter.odt b/docs/showcase/newsletter.odt index 941da86..f46e3d0 100644 Binary files a/docs/showcase/newsletter.odt and b/docs/showcase/newsletter.odt differ diff --git a/docs/showcase/newsletter.png b/docs/showcase/newsletter.png index 8ac1391..72f7a6a 100644 Binary files a/docs/showcase/newsletter.png and b/docs/showcase/newsletter.png differ diff --git a/docs/showcase/thesis-contents.png b/docs/showcase/thesis-contents.png index b5e0357..66c49d1 100644 Binary files a/docs/showcase/thesis-contents.png and b/docs/showcase/thesis-contents.png differ diff --git a/docs/showcase/thesis-overview.png b/docs/showcase/thesis-overview.png index 0866bc7..9122950 100644 Binary files a/docs/showcase/thesis-overview.png and b/docs/showcase/thesis-overview.png differ diff --git a/docs/showcase/thesis-review.docx b/docs/showcase/thesis-review.docx index 45084c1..eddb636 100644 Binary files a/docs/showcase/thesis-review.docx and b/docs/showcase/thesis-review.docx differ diff --git a/docs/showcase/thesis-review.odt b/docs/showcase/thesis-review.odt index 871c2a5..fb85c56 100644 Binary files a/docs/showcase/thesis-review.odt and b/docs/showcase/thesis-review.odt differ diff --git a/docs/showcase/thesis-review.png b/docs/showcase/thesis-review.png index 7fdfcaf..25f492b 100644 Binary files a/docs/showcase/thesis-review.png and b/docs/showcase/thesis-review.png differ diff --git a/docs/showcase/thesis.docx b/docs/showcase/thesis.docx index 9cecce7..e091a95 100644 Binary files a/docs/showcase/thesis.docx and b/docs/showcase/thesis.docx differ diff --git a/docs/showcase/thesis.odt b/docs/showcase/thesis.odt index ff9fa4f..207ec08 100644 Binary files a/docs/showcase/thesis.odt and b/docs/showcase/thesis.odt differ diff --git a/scripts/showcase/book.ts b/scripts/showcase/book.ts index f3b8236..3cee216 100644 --- a/scripts/showcase/book.ts +++ b/scripts/showcase/book.ts @@ -79,7 +79,7 @@ export async function build(): Promise { props: { title: 'Alice’s Adventures in Wonderland', subject: '', author: 'Lewis Carroll', keywords: '', description: '' }, shots: [ { file: 'book', page: 3 }, - { file: 'book-spread', page: 3, columns: 2 }, + { file: 'book-spread', page: 3, columns: 2, tab: 'layout' }, ], }; } diff --git a/scripts/showcase/lib.ts b/scripts/showcase/lib.ts index 18ebc7e..5dff77e 100644 --- a/scripts/showcase/lib.ts +++ b/scripts/showcase/lib.ts @@ -93,6 +93,8 @@ export type Shot = { file: string; page?: number; at?: string; zoom?: number; theme?: 'light' | 'dark'; /** Pages side by side (View ▸ page columns). */ columns?: number; markup?: boolean; spelling?: boolean; + /** The ribbon tab to open, and where to put the caret (first match in view). */ + tab?: string; caret?: string; }; export type Showcase = { diff --git a/scripts/showcase/newsletter.ts b/scripts/showcase/newsletter.ts index 9e85a6a..00cc452 100644 --- a/scripts/showcase/newsletter.ts +++ b/scripts/showcase/newsletter.ts @@ -112,8 +112,8 @@ export async function build(): Promise { hyphenate: true, props: { title: 'Newsletter 3/2026', subject: 'Eden Astronomy Society', author: 'The committee', keywords: 'astronomy, society', description: '' }, shots: [ - { file: 'newsletter', page: 1 }, - { file: 'newsletter-tables', page: 2 }, + { file: 'newsletter', page: 1, tab: 'layout' }, + { file: 'newsletter-tables', page: 2, tab: 'tableLayout', caret: '.tiptap table td' }, ], }; } diff --git a/scripts/showcase/run.mjs b/scripts/showcase/run.mjs index 32bb54b..a604f98 100644 --- a/scripts/showcase/run.mjs +++ b/scripts/showcase/run.mjs @@ -74,11 +74,13 @@ try { 'edentext-markup-mode': shot.markup ? 'all' : 'none', 'edentext-page-columns': String(shot.columns ?? 1), }); - // Unknown names would wear squiggles in every shot; the review shot keeps them. - if (!shot.spelling) await page.addStyleTag({ content: '.pm-spell-error { text-decoration: none !important; background: none !important; }' }); + // Unknown names would wear squiggles in every shot; the review shot keeps them. The + // floating table toolbar would cover the table the ribbon is already showing. + await page.addStyleTag({ content: `.table-toolbar { display: none !important; } + ${shot.spelling ? '' : '.pm-spell-error { text-decoration: none !important; background: none !important; }'}` }); // One .paper holds every page; page n starts n-1 page cycles down it. The caret // goes to the first paragraph in view, so the ribbon shows the body's formatting. - await page.evaluate(({ page: n, at }) => { + await page.evaluate(({ page: n, at, caret }) => { const editor = document.querySelector('.editor'); const paper = document.querySelector('.paper'); const cycle = parseFloat(getComputedStyle(paper).getPropertyValue('--page-height')) + 20; @@ -91,10 +93,15 @@ try { editor.scrollTop = top + (n - 1) * cycle * zoom - 12; const limit = editor.getBoundingClientRect().top + 40; const plain = (p) => [...p.querySelectorAll('*')].every((e) => /^(SPAN|STRONG|EM|B|I|U|S|A|SUP|SUB|BR)$/.test(e.tagName)); - const first = [...document.querySelectorAll('.tiptap > p')].find((p) => p.getBoundingClientRect().top > limit && p.textContent.trim() && plain(p)); + // A `caret` selector puts it in that element instead — a table cell brings up the + // contextual tabs, so the ribbon shows what the shot is about. + const first = caret + ? [...document.querySelectorAll(caret)].find((e) => e.getBoundingClientRect().top > limit) + : [...document.querySelectorAll('.tiptap > p')].find((p) => p.getBoundingClientRect().top > limit && p.textContent.trim() && plain(p)); const view = document.querySelector('.tiptap').editor; if (first) view.commands.focus(view.view.posAtDOM(first, 0) + 1, { scrollIntoView: false }); - }, { page: shot.page ?? 1, at: shot.at }); + }, { page: shot.page ?? 1, at: shot.at, caret: shot.caret }); + if (shot.tab) await page.click(`.ribbon-tab[data-tab="${shot.tab}"]`); await page.waitForTimeout(500); await page.screenshot({ path: join(OUT, `${shot.file}.png`) }); console.log(` ${shot.file}.png`); diff --git a/scripts/showcase/thesis.ts b/scripts/showcase/thesis.ts index 96a70ba..041193d 100644 --- a/scripts/showcase/thesis.ts +++ b/scripts/showcase/thesis.ts @@ -186,12 +186,12 @@ export function build(review = false): Showcase { decor: review ? { background: null, border: null, watermark: { text: 'DRAFT', font: 'Liberation Sans', color: '#C8C8C8', angle: 45, transparency: 60 } } : undefined, shots: review - ? [{ file: 'thesis-review', at: 'Introduction', markup: true }] + ? [{ file: 'thesis-review', at: 'Introduction', markup: true, tab: 'review' }] : [ { file: 'thesis', at: 'Method' }, { file: 'thesis-dark', at: 'Method', theme: 'dark' }, - { file: 'thesis-contents', at: 'Contents' }, - { file: 'thesis-overview', page: 1, zoom: 50, columns: 2 }, + { file: 'thesis-contents', at: 'Contents', tab: 'references' }, + { file: 'thesis-overview', page: 1, zoom: 50, columns: 2, tab: 'view' }, ], }; } diff --git a/src/lib/components/ribbon/Ribbon.svelte b/src/lib/components/ribbon/Ribbon.svelte index 1a2d854..056d07a 100644 --- a/src/lib/components/ribbon/Ribbon.svelte +++ b/src/lib/components/ribbon/Ribbon.svelte @@ -278,6 +278,7 @@ {#each shown as id}