From 179507fb7bd2b7e031ab2700560f4dd2f45c67d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Fri, 4 Sep 2026 16:55:48 +0100 Subject: [PATCH] the rich text editor offers three heading levels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One button that toggled H2, so a document could hold exactly one weight of heading — and the levels the site's sanitiser already accepted were unreachable from the editor that writes for it. Three buttons rather than a dropdown: they are toggles like everything else on the bar, the active one answers "what is this line", and a select would hide that behind a click. A level is a rank in the outline and never a size. What each draws at is the site's — three of the four type roles, in the prose rules — so the Layout section stays the one place type is sized. `[open]` H1 is offered because it was asked for, and a page that already has a title now has two. That is an outline a search engine reads as two documents, and it wants a rule about where H1 belongs before this gets used much. Co-Authored-By: Claude Opus 5 (1M context) --- web/RichText.tsx | 47 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/web/RichText.tsx b/web/RichText.tsx index 5e01cb4..cf7aa3e 100644 --- a/web/RichText.tsx +++ b/web/RichText.tsx @@ -9,7 +9,9 @@ import { AlignLeft, AlignRight, Bold, + Heading1, Heading2, + Heading3, Italic, Link2, List, @@ -44,6 +46,24 @@ import { * somewhere that is not typing — see the effect below. */ +/** + * The heading levels the bar offers, in the order they nest. + * + * A level is a rank in the document's outline, and the SIZE it draws at is the site's — see the prose + * rules in styles.css, where each maps to one of the four type roles. So this list says what a heading + * means and never what it looks like, which is the only way the Layout section can go on being the + * place type is sized. + * + * `[open]` H1 is offered because it was asked for, and a page that already has a title now has two — + * which is an outline a search engine reads as two documents. Worth a rule about where H1 belongs + * before this is used much. + */ +const HEADINGS = [ + { level: 1 as const, Icon: Heading1, label: 'Heading 1' }, + { level: 2 as const, Icon: Heading2, label: 'Heading 2' }, + { level: 3 as const, Icon: Heading3, label: 'Heading 3' }, +]; + const Tool = ({ onClick, active, @@ -107,13 +127,26 @@ const Toolbar = ({ editor }: { editor: Editor }) => ( - editor.chain().focus().toggleHeading({ level: 2 }).run()} - active={editor.isActive('heading', { level: 2 })} - > - - + {/* + Three levels, not one. + + It was a single button that toggled H2, so a document could hold exactly one weight of heading — + and the two levels the site's sanitiser already allowed were unreachable from the editor that + writes for it. + + Three buttons rather than a dropdown: they are toggles like everything else on this bar, the + active one is the answer to "what is this line", and a select would hide that behind a click. + */} + {HEADINGS.map(({ level, Icon, label }) => ( + editor.chain().focus().toggleHeading({ level }).run()} + active={editor.isActive('heading', { level })} + > + + + ))} editor.chain().focus().toggleBulletList().run()}