diff --git a/.changeset/inline-code-prose-flow.md b/.changeset/inline-code-prose-flow.md new file mode 100644 index 00000000..496f2a32 --- /dev/null +++ b/.changeset/inline-code-prose-flow.md @@ -0,0 +1,5 @@ +--- +"@luzzle/web": patch +--- + +Let inline code flow with prose without forced italics, retaining its background, padding, and rounded corners. Fenced code blocks are unchanged. diff --git a/.changeset/keyboard-desktop-sidenotes.md b/.changeset/keyboard-desktop-sidenotes.md new file mode 100644 index 00000000..8c7d4279 --- /dev/null +++ b/.changeset/keyboard-desktop-sidenotes.md @@ -0,0 +1,6 @@ +--- +"@luzzle/web": patch +"@luzzle/web.worker": patch +--- + +Show clickable, three-line desktop sidenote previews with viewport-fitted native popovers. Keep scrollable bottom sheets on phones and tablets, with native keyboard controls, Escape and outside-click dismissal, and no application JavaScript. diff --git a/.changeset/label-markdown-task-checkboxes.md b/.changeset/label-markdown-task-checkboxes.md new file mode 100644 index 00000000..2a016b7f --- /dev/null +++ b/.changeset/label-markdown-task-checkboxes.md @@ -0,0 +1,5 @@ +--- +"@luzzle/web.worker": patch +--- + +Label rendered Markdown task-list checkboxes with their task descriptions, preserving their checked and disabled states. diff --git a/.changeset/native-sidenote-popovers.md b/.changeset/native-sidenote-popovers.md new file mode 100644 index 00000000..ac8b5155 --- /dev/null +++ b/.changeset/native-sidenote-popovers.md @@ -0,0 +1,6 @@ +--- +"@luzzle/web": patch +"@luzzle/web.worker": patch +--- + +Show sidenotes as native bottom sheets on phones and tablets, with whole-sheet scrolling, a subtle backdrop, and the note number as a close button. Keep visible margin notes on wide screens without application JavaScript. diff --git a/.changeset/readable-quote-paragraphs.md b/.changeset/readable-quote-paragraphs.md new file mode 100644 index 00000000..ab1d68ff --- /dev/null +++ b/.changeset/readable-quote-paragraphs.md @@ -0,0 +1,5 @@ +--- +"@luzzle/web": patch +--- + +Preserve paragraph breaks in Markdown quotes, leave italics to authored emphasis, and use a thinner border with body-relative padding while retaining the background, rounded corners, and shadow. diff --git a/.changeset/responsive-browser-font-sizing.md b/.changeset/responsive-browser-font-sizing.md new file mode 100644 index 00000000..8d373032 --- /dev/null +++ b/.changeset/responsive-browser-font-sizing.md @@ -0,0 +1,6 @@ +--- +"@luzzle/web": patch +"@luzzle/web.worker": patch +--- + +Restore configured responsive browser font sizing while keeping Open Graph typography fixed. diff --git a/.changeset/scroll-wide-markdown-content.md b/.changeset/scroll-wide-markdown-content.md new file mode 100644 index 00000000..75512847 --- /dev/null +++ b/.changeset/scroll-wide-markdown-content.md @@ -0,0 +1,5 @@ +--- +"@luzzle/web": patch +--- + +Keep fenced code and wide tables within the reading column and let readers scroll them horizontally without widening the page. Tables use their natural width, capped at the column width. diff --git a/.changeset/shared-reading-typography.md b/.changeset/shared-reading-typography.md new file mode 100644 index 00000000..8ccac216 --- /dev/null +++ b/.changeset/shared-reading-typography.md @@ -0,0 +1,5 @@ +--- +"@luzzle/web": patch +--- + +Give rendered Markdown shared prose typography and simplify the note page's headline scale and reading-column gutters. diff --git a/apps/web/demo/archive/words/a-way-with-words.words.md b/apps/web/demo/archive/words/a-way-with-words.words.md index a2229a09..6cbfc8fb 100644 --- a/apps/web/demo/archive/words/a-way-with-words.words.md +++ b/apps/web/demo/archive/words/a-way-with-words.words.md @@ -1,5 +1,5 @@ --- -title: Untitled Words Piece +title: "Markdown: A Typographical Exploration" subtitle: the subtitle summary: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim @@ -8,85 +8,83 @@ summary: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do keywords: lorem, ipsum, dolor, sit, amet, consectetur, adipiscing, elit, quisque, dictum date_published: 2025-11-11 --- -# Markdown: A Typographical Exploration - -## Introduction - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse potenti. Nullam finibus, nulla ac suscipit sollicitudin, enim felis commodo turpis, nec maximus ex enim in quam. Aenean in ultrices massa. In hac habitasse platea dictumst. Curabitur sit amet consequat odio, nec egestas velit. - -## The Fundamentals of Emphasis - -Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In hac habitasse platea dictumst. Vivamus ut **elementum dolor**, sed aliquet dolor. Aliquam erat volutpat. *Nunc ut tellus in ipsum* commodo ultricies. Sed tristique, ***justo nec lobortis*** consequat, mi quam efficitur libero, atb `maximus()` erat ipsum. ~~Donec efficitur~~, lacus sed bibendum cursus, mi massa commodo sem, a commodo arcu ex sit amet quam. Integer nec mi non metus `viverra()` sodales. - -## Citations and Visual Aides - -Nulla facilisi. [Aenean euismod](https://example.com "aliquam quaerat voluptatem") bibendum laoreet . Proin gravida dolor sit amet lacus accumsan et viverra justo commodo. Proin sodales pulvinar sic tempor. Sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nam fermentum, nulla luctus pharetra vulputate, felis tellus mollis orci, sed rhoncus pronin sapien nunc accuan. - -![An opengraph image](/images/opengraph.png "opengraph image") - -## Structuring Data - -Maecenas malesuada. Praesent congue erat at massa. Sed cursus turpis vitae tortor. Donec posuere vulputate arcu. Phasellus accumsan cursus velit. - -1. Primum, vestibulum ante ipsum primis in faucibus orci luctus. -2. Secundo, ultrices posuere cubilia Curae; Morbi lacinia molestie dui. -3. Tertio, praesent blandit dolor. Sed non quam. - -In vel mi sit amet augue congue elementum. Morbi in sem quis dui placerat ornare. Pellentesque odio nisi, euismod in, pharetra a, ultricies in, diam. -* Item primarium - * Item secundarium - * Aliud item secundarium -* Item aliud primarium -* Item ultimum primarium - -## Quoting Sources - -Cras ultricies mi eu turpis hendrerit fringilla. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In ac dui quis mi consectetuer lacinia. Nam pretium turpis et arcu. - -> Duis arcu tortor, suscipit eget, imperdiet nec, imperdiet iaculis, ipsum. Sed aliquam ultrices mauris. Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris. Praesent adipiscing. Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. - ---- - -## Managing Tasks - -Vestibulum volutpat pretium libero. Cras id dui. Aenean ut eros et nisl sagittis vestibulum. Nullam nulla eros, ultricies sit amet, nonummy id, imperdiet feugiat, pede. - -- [x] Complete initial research on *lorem ipsum*. -- [ ] Draft the main body of the text. -- [ ] Review and finalize the typographical elements. - -## Tabulating Data - -Morbi nec metus. Phasellus blandit leo ut odio. Maecenas ullamcorper, dui et placerat feugiat, eros pede varius nisi, condimentum viverra felis nunc et lorem. Sed magna purus, fermentum eu, tincidunt eu, varius ut, felis. Below is a summary of findings. - -| Header 1 (left) | Header 2 (center) | Header 3 (right) | -|:-------------|:-------------------------:|-------------------------:| -| *Lorem* | `ipsum` | Dolor sit amet | -| Consectetur | Adipiscing | Elit | -| Nunc | **viverra** | Imperdiet | - -## Technical Examples - -In ultrices, libero non varius commodo, sem justo rutrum elit, sed pulvinar felis felis ac quam. Uta `example.js` scriptum, quod infra monstratur, hoc modo uti potest: - -```javascript title="hello.js" -/** - * A simple lorem ipsum function. - */ -function greet(name) { - // Return a classic greeting - console.log(`Lorem ipsum, ${name}!`); -} - -greet('Mundo'); -``` - -## Asides and Annotations - -Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, quis gravida magna mi a libero. Fusce vulputate eleifend sapien. Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus.[^1] Nullam accumsan lorem in dui. - -## Conclusion - -Curabitur turpis. Vestibulum facilisis, purus nec pulvinar iaculis, ligula mi congue nunc, vitae euismod ligula urna in dolor. Mauris sollicitudin fermentum libero. Praesent nonummy mi in odio. Nunc interdum lacus sit amet orci. - +## Introduction + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse potenti. Nullam finibus, nulla ac suscipit sollicitudin, enim felis commodo turpis, nec maximus ex enim in quam. Aenean in ultrices massa. In hac habitasse platea dictumst. Curabitur sit amet consequat odio, nec egestas velit. + +## The Fundamentals of Emphasis + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In hac habitasse platea dictumst. Vivamus ut **elementum dolor**, sed aliquet dolor. Aliquam erat volutpat. *Nunc ut tellus in ipsum* commodo ultricies. Sed tristique, ***justo nec lobortis*** consequat, mi quam efficitur libero, atb `maximus()` erat ipsum. ~~Donec efficitur~~, lacus sed bibendum cursus, mi massa commodo sem, a commodo arcu ex sit amet quam. Integer nec mi non metus `viverra()` sodales. + +## Citations and Visual Aides + +Nulla facilisi. [Aenean euismod](https://example.com "aliquam quaerat voluptatem") bibendum laoreet . Proin gravida dolor sit amet lacus accumsan et viverra justo commodo. Proin sodales pulvinar sic tempor. Sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nam fermentum, nulla luctus pharetra vulputate, felis tellus mollis orci, sed rhoncus pronin sapien nunc accuan. + +![An opengraph image](/images/opengraph.png "opengraph image") + +## Structuring Data + +Maecenas malesuada. Praesent congue erat at massa. Sed cursus turpis vitae tortor. Donec posuere vulputate arcu. Phasellus accumsan cursus velit. + +1. Primum, vestibulum ante ipsum primis in faucibus orci luctus. +2. Secundo, ultrices posuere cubilia Curae; Morbi lacinia molestie dui. +3. Tertio, praesent blandit dolor. Sed non quam. + +In vel mi sit amet augue congue elementum. Morbi in sem quis dui placerat ornare. Pellentesque odio nisi, euismod in, pharetra a, ultricies in, diam. +* Item primarium + * Item secundarium + * Aliud item secundarium +* Item aliud primarium +* Item ultimum primarium + +## Quoting Sources + +Cras ultricies mi eu turpis hendrerit fringilla. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In ac dui quis mi consectetuer lacinia. Nam pretium turpis et arcu. + +> Duis arcu tortor, suscipit eget, imperdiet nec, imperdiet iaculis, ipsum. Sed aliquam ultrices mauris. Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris. Praesent adipiscing. Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. + +--- + +## Managing Tasks + +Vestibulum volutpat pretium libero. Cras id dui. Aenean ut eros et nisl sagittis vestibulum. Nullam nulla eros, ultricies sit amet, nonummy id, imperdiet feugiat, pede. + +- [x] Complete initial research on *lorem ipsum*. +- [ ] Draft the main body of the text. +- [ ] Review and finalize the typographical elements. + +## Tabulating Data + +Morbi nec metus. Phasellus blandit leo ut odio. Maecenas ullamcorper, dui et placerat feugiat, eros pede varius nisi, condimentum viverra felis nunc et lorem. Sed magna purus, fermentum eu, tincidunt eu, varius ut, felis. Below is a summary of findings. + +| Header 1 (left) | Header 2 (center) | Header 3 (right) | +|:-------------|:-------------------------:|-------------------------:| +| *Lorem* | `ipsum` | Dolor sit amet | +| Consectetur | Adipiscing | Elit | +| Nunc | **viverra** | Imperdiet | + +## Technical Examples + +In ultrices, libero non varius commodo, sem justo rutrum elit, sed pulvinar felis felis ac quam. Uta `example.js` scriptum, quod infra monstratur, hoc modo uti potest: + +```javascript title="hello.js" +/** + * A simple lorem ipsum function. + */ +function greet(name) { + // Return a classic greeting + console.log(`Lorem ipsum, ${name}!`); +} + +greet('Mundo'); +``` + +## Asides and Annotations + +Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, quis gravida magna mi a libero. Fusce vulputate eleifend sapien. Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus.[^1] Nullam accumsan lorem in dui. + +## Conclusion + +Curabitur turpis. Vestibulum facilisis, purus nec pulvinar iaculis, ligula mi congue nunc, vitae euismod ligula urna in dolor. Mauris sollicitudin fermentum libero. Praesent nonummy mi in odio. Nunc interdum lacus sit amet orci. + [^1]: Haec est leo annotatio sive nota pedalis diff --git a/apps/web/e2e/support/fixture.ts b/apps/web/e2e/support/fixture.ts index 1da8c22e..7f612e71 100644 --- a/apps/web/e2e/support/fixture.ts +++ b/apps/web/e2e/support/fixture.ts @@ -13,6 +13,20 @@ export const notebook = { title: 'Meteor Notebook' } +const note = `Original observation. + +> First quoted paragraph. +> +> Second quoted paragraph. +` +const noteHtml = `
+

Original observation.

+
+

First quoted paragraph.

+

Second quoted paragraph.

+
+
` + const pieces = [ notebook, { @@ -46,7 +60,7 @@ export async function createFixture(directory: string, origin: string) { for (const piece of pieces) { await writeFile( path.join(archive, piece.file), - `---\ntitle: ${piece.title}\ndate: ${dateConsumed}\n---\n\nOriginal observation.\n` + `---\ntitle: ${piece.title}\ndate: ${dateConsumed}\n---\n\n${note}` ) } const database = path.join(directory, 'data/luzzle.sqlite') @@ -58,7 +72,13 @@ export async function createFixture(directory: string, origin: string) { paths: { database }, content: { text: { title: 'E2E Garden' } }, auth: { secret: 'e2e-only-session-secret-at-least-32-characters', credentials: ADMIN }, - pieces: [{ type: 'notes', fields: { title: 'title', date_consumed: 'date' } }] + pieces: [ + { + type: 'notes', + fields: { title: 'title', date_consumed: 'date' }, + templates: { page: { name: 'note' } } + } + ] }) ) const db = createAppDb(database) @@ -82,13 +102,27 @@ export async function createFixture(directory: string, origin: string) { type: piece.type, file_path: piece.file, title: piece.title, - note: 'Original observation.', + note, json_metadata: JSON.stringify({ title: piece.title, date: dateConsumed }), date_added: consumedAt, date_consumed: consumedAt })) ) .execute() + await db + .insertInto('web_pieces_assets') + .values( + pieces.map((piece) => ({ + piece_file_path: piece.file, + piece_key: piece.slug, + asset_key: piece.slug, + transformation: 'markdown', + mime_type: 'text/html', + is_embedded: 1, + content: noteHtml + })) + ) + .execute() } finally { await db.destroy() } diff --git a/apps/web/e2e/typography.e2e.ts b/apps/web/e2e/typography.e2e.ts new file mode 100644 index 00000000..5184fe2f --- /dev/null +++ b/apps/web/e2e/typography.e2e.ts @@ -0,0 +1,27 @@ +import { expect, test } from './support/test.js' +import { notebook } from './support/fixture.js' + +test('root font sizing responds to the viewport instead of staying fixed', async ({ page }) => { + await page.setViewportSize({ width: 390, height: 900 }) + await page.goto(notebook.publicUrl) + const phoneSize = await page + .locator('html') + .evaluate((element) => parseFloat(getComputedStyle(element).fontSize)) + + await page.setViewportSize({ width: 1440, height: 900 }) + const desktopSize = await page + .locator('html') + .evaluate((element) => parseFloat(getComputedStyle(element).fontSize)) + expect(phoneSize).toBeLessThan(desktopSize) +}) + +test('quoted paragraphs remain visually separated', async ({ page }) => { + await page.setViewportSize({ width: 390, height: 900 }) + await page.goto(notebook.publicUrl) + const quote = page.locator('main .markdown blockquote') + const paragraphGap = await quote.evaluate((element) => { + const [first, second] = element.querySelectorAll('p') + return second.getBoundingClientRect().top - first.getBoundingClientRect().bottom + }) + expect(paragraphGap).toBeGreaterThan(0) +}) diff --git a/packages/web/templates/src/pages/note/template.svelte b/packages/web/templates/src/pages/note/template.svelte index 197bbec6..f1d30c8d 100644 --- a/packages/web/templates/src/pages/note/template.svelte +++ b/packages/web/templates/src/pages/note/template.svelte @@ -57,20 +57,19 @@