Skip to content

feat: add text color and highlight marks - #84

Merged
ma2za merged 2 commits into
ma2za:mainfrom
und1sk0:feature/text-color-and-highlight
Oct 23, 2026
Merged

ma2za merged 2 commits into
ma2za:mainfrom
und1sk0:feature/text-color-and-highlight

Conversation

@und1sk0

@und1sk0 und1sk0 commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds textStyle and highlight ProseMirror marks for text color and highlight, since Substack's editor supports both but the library had no way to produce them.

  • New node builders in substack/nodes.py: text_style_mark(color), highlight_mark(color).
  • Markdown round-trip via Pandoc-style span attributes: [text]{style="color:#hex"} and [text]{style="background-color:#hex"}, combinable in one span ({style="color:#fff; background-color:#000"}). Restricted to spans only (not after images/links/code), so a stray {...} elsewhere stays plain text.
  • Unrecognized style declarations are ignored rather than rejected, since the same [text]{...} syntax is used by the attrs plugin for other attributes too.

Why this mark shape

I didn't want to guess the schema, so I checked it against a real Substack draft: applied both marks via the API directly, published, and read the rendered HTML back from the public post endpoint. textStyle renders as <span data-color="#hex" style="color: rgb(...)">, confirming it's a standard Tiptap TextStyle-family mark (same pattern Substack already uses for existing colored text, which I found in an export). highlight renders as <mark data-color="#hex" style="background-color: rgb(...); color: rgb(...)"> (Substack also auto-picks a readable text color for contrast) — this one wasn't previously confirmed anywhere, so I verified it the same way before writing any code against it.

You can see both live, on the actual draft used to verify them: https://und1sk0.substack.com/p/ai-bullshittery

Test plan

  • New offline tests for parsing (test_from_markdown_features.py) and export/round-trip (test_markdown_export.py), including combined color+highlight and malformed-mark-as-opaque-node cases.
  • Full offline suite passes: poetry run pytest -q -m "not live" --strict-markers (278 passed).
  • pre-commit run --all-files clean.
  • Updated docs/markdown.md, README.md, and CHANGELOG.md per CONTRIBUTING.md.

🤖 Generated with Claude Code

und1sk0 and others added 2 commits October 10, 2026 11:30
Adds textStyle and highlight ProseMirror marks (node builders in
substack/nodes.py), with Markdown round-trip via Pandoc-style span
attributes: [text]{style="color:#hex"} and
[text]{style="background-color:#hex"}, combinable in one span.

Verified against Substack's real editor schema by applying both marks
to a live draft and reading the rendered HTML back: textStyle becomes
a <span data-color> with inline color, highlight becomes a <mark
data-color> with inline background-color.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@ma2za
ma2za merged commit d161202 into ma2za:main Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants