Skip to content

Publishing module improvements and bug fixes - #425

Merged
ddon merged 15 commits into
BeamLabEU:devfrom
mdon:dev
Mar 17, 2026
Merged

Publishing module improvements and bug fixes#425
ddon merged 15 commits into
BeamLabEU:devfrom
mdon:dev

Conversation

@mdon

@mdon mdon commented Mar 17, 2026

Copy link
Copy Markdown
Contributor

TL;DR

Fixes language handling bugs, adds SEO meta tags, improves editor UX, and fixes several edge cases in the publishing module.


Publishing Module Improvements

SEO & Meta Tags

  • Add Open Graph and Twitter Card meta tags for public publishing pages (posts, listings, versioned posts)

Language Handling

  • Fix language map lookup when canonical URL uses base code (e.g., "en" → "en-US" matching)
  • Increase language switcher selection visibility on dark themes (30% opacity)
  • Fix translation reload showing primary language content instead of translated content
  • Fix PubSub subscription mismatch for translation/version events on timestamp-mode posts

Editor UX

  • Remove auto-title/slug from content, add real-time title-driven slug generation
  • Show full public interface in preview with working language switcher
  • Show indeterminate state for translation progress until data arrives
  • Move save indicator above title, remove Content heading
  • Hide preview button when creating a new post
  • Add warning flash kind for new post language switching

Navigation

  • Use live navigation on public publishing pages for smooth transitions

Bug Fixes

  • Fix email template seeding failing on fresh install
  • Fix whitespace in slug format examples
  • Add startup warning when PhoenixKit is not installed

mdon and others added 15 commits March 17, 2026 22:26
Logs a warning on application start if PhoenixKit is added as a
dependency but not configured, directing users to run mix phoenix_kit.install.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
seed_system_templates passes plain strings for multilingual fields
(display_name, subject, html_body, etc.) but the Template schema
expects i18n maps (%{"en" => "value"}). Wrap string values in
language maps before passing to create_template.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The preview button requires a saved post UUID to build the preview URL.
On the new post page the UUID is nil, making the button non-functional.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The flash component only supported :info and :error kinds, but :warning
was already used in other parts of the codebase without being rendered.
Add :warning with alert-warning styling and triangle icon. Use it for
the language switch hint on unsaved new posts instead of :error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace content-based auto-extraction of title (from H1 heading) and
slug with explicit title input and real-time slug generation from title.

- Remove maybe_update_title_from_content, preserve_auto_title,
  detect_title_manual_set, revert_title_to_auto, and all title
  tracking assigns (title_manually_set, last_auto_title)
- Replace maybe_update_slug_from_content with maybe_update_slug_from_title
  that generates slug directly from the title field
- Title and slug are required to save (autosave silently skips if empty)
- Slug manual-set detection uses _target to avoid stale browser values
- Preserve server-side slug when user is typing in title field
- Detect slug constraint errors on post creation and show clear message
- Add editor forms unit tests and slug update integration tests
- Update template help text and remove phx:update-title JS listener

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
reload_translated_content and reload_post called re_read_post without
passing the current language, causing read_post_by_uuid to fall back to
the primary language. After a successful translation, the editor would
show English content instead of the translated content until refresh.

Pass current_language to re_read_post in all places that reload content.
Add integration test verifying language-specific content retrieval.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the bare markdown preview with the full public post layout
including breadcrumbs, publication date, language switcher, version
dropdown, title, and styled content. Language links navigate within
the preview instead of going to the public site. Breadcrumbs are
non-interactive.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace <a href> links with <.link navigate> across all public
templates for smooth client-side transitions instead of full page
refreshes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Display "Starting..." with an animated progress bar instead of "0/0"
when translation is enqueued but progress info hasn't been received yet.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The editor subscribed to translation/version topics using post.slug
only, but the worker broadcasts using slug || uuid. Timestamp-mode
posts (no slug) never received translation events because the topic
didn't match.

- Add PubSub.broadcast_id/1 as the single source of truth for post
  identifier resolution (slug || uuid)
- Update collaborative subscriptions to use broadcast_id
- Update translation worker to use broadcast_id
- Fix translation_created handler to pass current_language
- Remove unused default on re_read_post (compiler enforces language arg)
- Add tests for broadcast_id and topic consistency

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Render og:title, og:description, og:image, og:url, og:locale, og:type,
canonical link, and Twitter Card tags in the root layout when @og assign
is present. Build OG data from post metadata, description, and featured
image in the publishing controller for posts, versioned posts, date-only
URLs, and group listings.

Use conn.scheme/host/port for base URL instead of Endpoint.url() to
avoid compile-time dependency on the parent app endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When only one dialect is enabled (e.g., "en-US"), canonical URLs use the base
code ("en") for cleaner paths. However, language maps (language_titles,
language_excerpts, language_slugs) store data using full dialect codes as keys.
This caused Map.get lookups to fail when the language param was a base code but
the map only had dialect code keys.

Added resolve_language_key/2 helper to try exact match first, then match by
base code when looking up language-specific data in listing and URL generation.
Changed bg-primary/10 to bg-primary/30 for selected language background,
making it more visible on dark themes where 10% opacity was nearly invisible.
@ddon
ddon merged commit ffc3314 into BeamLabEU:dev Mar 17, 2026
4 of 6 checks passed
ddon added a commit that referenced this pull request Mar 17, 2026
Extract duplicated resolve_language_key/2 to shared LanguageHelpers helper. Fix absolute_url/2 to use stricter URL protocol checking. Add og:site_name meta tag. Fix preview language links to conditionally include version. Add PR review documentation.
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