Skip to content

Add blogging module enhancements: video components, metadata extraction, and code quality improvements - #180

Merged
ddon merged 9 commits into
BeamLabEU:devfrom
mdon:dev
Nov 13, 2025
Merged

Add blogging module enhancements: video components, metadata extraction, and code quality improvements#180
ddon merged 9 commits into
BeamLabEU:devfrom
mdon:dev

Conversation

@mdon

@mdon mdon commented Nov 13, 2025

Copy link
Copy Markdown
Contributor

Summary

This PR enhances the PhoenixKit blogging module with new features, improved metadata handling, and architectural fixes addressing code review feedback.

New Features

YouTube Video Component

  • Add responsive YouTube video embed component with multiple configuration options
  • Support for video URLs, IDs, autoplay, muted, controls, loop, start time
  • Multiple aspect ratios: 16:9, 4:3, 1:1, 21:9
  • Optional captions support
  • Integrated with blogging markdown renderer

Featured Images & Translation Support

  • Add featured image support for blog posts (stored in frontmatter)
  • Implement translation-aware language switcher for blog posts
  • Hide unpublished translations from public language switcher
  • Add featured image display in post listings

Improvements

Metadata Extraction Hardening

  • Fix title extraction when posts start with PHK components (Hero, Image, etc.)
  • Improve metadata parsing for component-heavy posts
  • Add fallback logic for missing titles
  • Better handling of mixed markdown/component content

Configuration Architecture Fixes

  • Breaking Change: Replace Application.get_env/3 with PhoenixKit.Config.get/2 in blogging module
  • Add config/test.exs for proper test environment configuration
  • Update blogging README to document correct test configuration patterns
  • Clarify FakeSettings as future implementation (tests not yet written)

Code Quality (Credo Fixes)

  • Add :error metadata key to Logger configuration
  • Add module aliases to reduce nested module references (8 occurrences)
  • Rename is_pure_phk_content? to pure_phk_content? (Elixir style guide)
  • Replace explicit try-rescue with implicit rescue for cleaner code
  • Optimize Enum operations: map |> joinmap_join (4 occurrences)
  • Combine double Enum.filter into single filter for better performance
  • Replace single-condition cond with if/else

Credo Result: 4754 mods/funs analyzed, 0 issues

Files Changed

New Features

  • lib/phoenix_kit_web/components/blogging/video.ex
  • Updates to blogging context for featured images and translations

Configuration

  • lib/phoenix_kit_web/live/modules/blogging/blogging.ex (Config pattern fix)
  • config/test.exs (new file)
  • config/config.exs (test config import + Logger metadata)

Documentation

  • lib/phoenix_kit_web/live/modules/blogging/README.md (test configuration docs)

Code Quality

  • lib/phoenix_kit/blogging/renderer.ex
  • lib/phoenix_kit/storage.ex
  • lib/phoenix_kit_web/components/blogging/hero.ex
  • lib/phoenix_kit_web/components/blogging/page.ex
  • lib/phoenix_kit_web/controllers/blog_controller.ex
  • lib/phoenix_kit_web/live/modules/blogging/context/page_builder/renderer.ex

Testing

  • All existing tests pass (26/29, 3 pre-existing rate limiter ETS cleanup issues)
  • Code compiles without warnings (except 1 unused function in editor.ex - pre-existing)
  • Credo static analysis: 0 issues
  • Code formatted with mix format

Migration Notes

For existing installations:

  • The configuration change from Application.get_env to PhoenixKit.Config.get is non-breaking (same interface)
  • config/test.exs is optional but recommended for test environments
  • No database migrations required
  • No user-facing breaking changes

Checklist

  • Code compiles without errors
  • Credo passes with no issues
  • Code formatted with mix format
  • Documentation updated
  • Follows PhoenixKit architectural patterns
  • Boss feedback addressed

This PR message tells a cohesive story of the improvements while providing clear sections for reviewers to understand the scope, impact, and quality of the
changes.

mdon added 9 commits November 13, 2025 22:25
- add `PhoenixKitWeb.Components.Blogging.Video`, wire it into the PHK renderer/inline markdown flow, and document usage in guides
- improve slug-mode storage to handle legacy posts without title/status and derive titles from content safely
- teach metadata title extraction to skip inline components so hero/video blocks don’t hide headings
- add missing Hammer config to the parent app so rate limiting boots in dev/test
- teach `Metadata.extract_title_from_content/1` to handle multi-line self-closing PHK components so opening tags like `<Video … />` no longer block headings from being detected
- ensure the title scanner decrements its component depth when it hits a trailing `/>`, allowing the subsequent Markdown `# Heading` to be promoted to the metadata title
- skip multi-line self-closing PHK components when scanning markdown so headings after blocks like <Video .../> are still detected
- add component-aware fallbacks: pull text from <Headline>...</Headline>, <Title>...</Title>, or Hero’s title attribute when no markdown heading exists
- sanitize captured component text before storing in metadata
- normalize the translation list so we always include the current language, but only show languages that are enabled and have a published translation file
- load each translation’s metadata to check status before rendering a badge/link, preventing drafts from appearing on the public post header
- extend blog metadata/frontmatter to store `featured_image_id`, propagate it through storage updates (slug + timestamp modes), and expose helper to resolve a public URL
- update the LiveView editor:
  * add a featured-image ID field with preview/validation, guide authors to Media Manager
  * include the new field in form normalization, post creation/update payloads, and metadata defaults so each translation can track its own image
  * fix the “View Public” button to build URLs with the current translation’s language, handling initial load/new translation states
- hide unpublished translations on the public language switcher by checking each translation’s `.phk` metadata before rendering badges
- show featured image thumbnails on the public blog index cards via the new helper
Fix architectural issues identified in code review:

1. Configuration Pattern Fix
   - Change blogging.ex line 367 to use PhoenixKit.Config.get instead of Application.get_env
   - Aligns with project-wide configuration management pattern
   - Maintains identical interface (non-breaking change)

2. Test Configuration Structure
   - Add config/test.exs with proper test environment settings
   - Configure test mailer with Swoosh.Adapters.Test
   - Set test-friendly Hammer rate limiting configuration
   - Update config.exs to import environment-specific configs

3. Documentation Updates
   - Mark FakeSettings as "Future Implementation" in blogging README
   - Document correct config/test.exs pattern (not runtime Application.put_env)
   - Clarify test status and future implementation approach
   - Update troubleshooting section with correct configuration examples

All changes follow standard Elixir/Phoenix configuration practices.
Address code quality improvements identified by Credo --strict:

1. Logger Metadata Warning
   - Add :error metadata key to Logger config to support error logging in preview.ex

2. Nested Module Aliases (Software Design)
   - Add module aliases to blogging/renderer.ex for PageBuilder, Image, Video, and Safe
   - Add module aliases to components/blogging/hero.ex and page.ex for Renderer
   - Replace long-form module references with aliased names
   - Sort aliases alphabetically per Elixir conventions

3. Code Readability
   - Rename is_pure_phk_content? to pure_phk_content? (remove 'is' prefix per Elixir style)
   - Replace explicit try-rescue with implicit rescue in storage.ex signed_file_url/2

4. Refactoring Opportunities
   - Replace Enum.map |> Enum.join with Enum.map_join in page_builder/renderer.ex
   - Combine double Enum.filter into single filter with combined predicate in blog_controller.ex
   - Replace cond with if/else in video.ex extract_standard_id/1 (only 2 conditions)

All changes improve code readability and performance while maintaining identical functionality.
Credo analysis: 4754 mods/funs, found no issues.
Address all code quality issues from CI/CD pipeline checks:

## Credo Fixes (Upstream Code)
- Replace explicit try-rescue with implicit rescue in repo_detection.ex:add_repo_config_to_files/2
- Remove unnecessary parentheses from config.ex:get_parent_app_fallback/0
- Both fixes improve code readability per Elixir style guide

## Dialyzer Fixes (Blogging Module)

### blogging/renderer.ex
- Remove unreachable is_binary guards in Image and Video rendering
- Simplify component rendering: always returns Phoenix.LiveView.Rendered struct
- Remove unreachable normalize_markdown/1 fallback clause (input always binary)

### components/blogging/video.ex
- Remove unreachable catch-all clauses in parse_uri/1 and classify_host/1
- Input types guaranteed by with statement guards

### controllers/blog_controller.ex
- Remove nil clause from normalize_languages/2
- Dialyzer proves available_languages is always a list, never nil

### live/modules/blogging/context/metadata.ex
- Fix Regex.run argument order: (regex, string, opts) not (string, regex, opts)
- Add missing featured_image_id field to metadata type spec
- Fixes invalid_contract and call errors

### live/modules/blogging/editor.ex
- Remove unused current_language/1 function
- Eliminates production compilation warning with --warnings-as-errors

## Verification
- Credo: 4751 mods/funs, 0 issues ✅
- Production compile: No warnings with --warnings-as-errors ✅
- All changes maintain identical runtime behavior
**Dialyzer Fixes:**

1. **basic_configuration.ex** - Fixed Igniter.Project.Config.configure_new calls
   - Changed config_path from atom to list format
   - `:parent_app_name` → `[:parent_app_name]`
   - `:parent_module` → `[:parent_module]`
   - Matches Igniter API signature: `configure_new(igniter, file_path, app_name, config_path_list, value)`

2. **editor.ex** - Removed unreachable guard in post.language check
   - Dialyzer proved `post.language` is always binary (never nil)
   - Removed unnecessary `language = post.language || editor_language(socket.assigns)`
   - Changed `build_public_url(post, language)` → `build_public_url(post, post.language)`
   - Guard `when binary() === nil` can never succeed

**Cascading Effect:**
- Installing/updating tasks showed "unused function" warnings due to type error blocking pipeline analysis
- These should resolve now that BasicConfiguration.add_basic_config/1 has correct return type

All fixes maintain identical runtime behavior while satisfying static type analysis.
@ddon
ddon merged commit 32512bb into BeamLabEU:dev Nov 13, 2025
6 checks passed
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