Add a text widget (rich text: bold/italic/underline, per-run color/highlight)
A new self-contained widget type showing user-authored rich text -- no
live upstream to poll, like the static image widget, just word-wrapped
styled text instead of an uploaded image.
The dialog's contenteditable HTML is never stored or replayed as HTML:
app/text_content.py parses it server-side (on save) into a plain
paragraphs-of-styled-runs structure -- the actual sanitization
boundary, since raw HTML never round-trips back into any browser DOM
(the dialog rebuilds its editor from that same JSON via
createElement/textContent). app/widgets/text.py renders it with a
custom word-wrap/shrink-to-fit layout, using real vendored font weights
(app/fonts/NotoSans-{Regular,Bold,Italic,BoldItalic}.ttf, OFL-licensed
like the emoji fonts already there) rather than every other widget's
single ImageFont.load_default() -- the one widget type where that
distinction matters.
This commit is contained in:
@@ -511,6 +511,14 @@ def _migration_20(conn) -> None:
|
||||
Base.metadata.create_all(bind=conn)
|
||||
|
||||
|
||||
def _migration_21(conn) -> None:
|
||||
"""New widget type: a text widget shows user-authored rich text (see
|
||||
app/text_content.py, app/widgets/text.py, models.TextWidgetConfig)
|
||||
-- another no-live-upstream type like migration 20's static image.
|
||||
Same brand-new-table create_all shape."""
|
||||
Base.metadata.create_all(bind=conn)
|
||||
|
||||
|
||||
MIGRATIONS = [
|
||||
(1, _migration_1),
|
||||
(2, _migration_2),
|
||||
@@ -532,6 +540,7 @@ MIGRATIONS = [
|
||||
(18, _migration_18),
|
||||
(19, _migration_19),
|
||||
(20, _migration_20),
|
||||
(21, _migration_21),
|
||||
]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user