diff --git a/blog/bp/post/admin/routes.py b/blog/bp/post/admin/routes.py index abec2d5..a4b86f2 100644 --- a/blog/bp/post/admin/routes.py +++ b/blog/bp/post/admin/routes.py @@ -23,6 +23,7 @@ def _post_to_edit_dict(post) -> dict: d: dict = {} for col in ( "id", "slug", "title", "html", "plaintext", "lexical", "mobiledoc", + "sx_content", "feature_image", "feature_image_alt", "feature_image_caption", "excerpt", "custom_excerpt", "visibility", "status", "featured", "is_page", "email_only", "canonical_url", @@ -595,6 +596,10 @@ def register(): effective_status = status sx_content_raw = form.get("sx_content", "").strip() or None + # Build optional kwargs — only pass sx_content if the form field was present + extra_kw: dict = {} + if "sx_content" in form: + extra_kw["sx_content"] = sx_content_raw try: post = await writer_update( g.s, @@ -606,7 +611,7 @@ def register(): custom_excerpt=custom_excerpt or None, feature_image_caption=feature_image_caption or None, status=effective_status, - sx_content=sx_content_raw, + **extra_kw, ) except OptimisticLockError: return redirect( diff --git a/blog/sx/sx_components.py b/blog/sx/sx_components.py index 602d08d..b4e49c2 100644 --- a/blog/sx/sx_components.py +++ b/blog/sx/sx_components.py @@ -1755,6 +1755,7 @@ def _post_edit_content_sx(ctx: dict) -> str: asset_url_fn = current_app.jinja_env.globals.get("asset_url", lambda p: "") editor_css = asset_url_fn("scripts/editor.css") editor_js = asset_url_fn("scripts/editor.js") + sx_editor_js = asset_url_fn("scripts/sx-editor.js") upload_image_url = qurl("blog.editor_api.upload_image") upload_media_url = qurl("blog.editor_api.upload_media") @@ -1773,6 +1774,7 @@ def _post_edit_content_sx(ctx: dict) -> str: updated_at = esc(ghost_post.get("updated_at") or "") status = ghost_post.get("status") or "draft" lexical_json = ghost_post.get("lexical") or '{"root":{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"root","version":1}}' + sx_content = ghost_post.get("sx_content") or "" already_emailed = bool(ghost_post and ghost_post.get("email") and (ghost_post["email"] if isinstance(ghost_post["email"], dict) else {}).get("status")) # For ORM objects the email may be an object @@ -1799,6 +1801,7 @@ def _post_edit_content_sx(ctx: dict) -> str: form_parts.append(f'') form_parts.append(f'') form_parts.append('') + form_parts.append(f'') form_parts.append(f'') form_parts.append(f'') @@ -1830,8 +1833,24 @@ def _post_edit_content_sx(ctx: dict) -> str: f' class="w-full text-[18px] text-stone-500 bg-transparent border-none outline-none placeholder:text-stone-300 resize-none mb-[24px] leading-relaxed">{excerpt_val}' ) - # Editor mount point - form_parts.append('
') + # Editor tabs: SX (primary) and Koenig (legacy) + has_sx = bool(sx_content) + sx_active = 'text-stone-700 border-b-2 border-stone-700 cursor-pointer bg-transparent' + sx_inactive = 'text-stone-400 border-b-2 border-transparent cursor-pointer bg-transparent hover:text-stone-600' + form_parts.append( + '