PhoenixKit.Modules.Publishing.Web.HTML (PhoenixKitPublishing v0.4.3)

Copy Markdown View Source

HTML rendering functions for Publishing.Web.Controller.

Summary

Functions

Pre-computes date counts for timestamp-mode posts to avoid per-post DB queries.

Builds a post URL based on mode. Omits the locale prefix when the site is effectively single-language. Can also omit the default-language prefix when that setting is enabled.

Builds a public path with explicit date and time (always includes time). Used when redirecting from date-only URLs to full timestamp URLs.

Builds language data for the publishing_language_switcher component on public pages. Converts the @translations assign to the format expected by the component.

Extracts and renders an excerpt from post content. Returns content before <!-- more --> tag, or first paragraph if no tag. Renders markdown and strips HTML tags for plain text display.

Resolves a featured image URL for a post, falling back to the original variant.

Formats a date for display using locale-aware month names.

Formats a date for URL.

Formats a date with time for display. Used when multiple posts exist on the same date.

Formats a post's publication date, including time only when multiple posts exist on the same date.

Formats time for URL (HH:MM).

Builds the public URL for a group listing page. Omits the locale prefix when the site is effectively single-language. Can also omit the default-language prefix when that setting is enabled.

Checks if a post has a publication date to display. For timestamp mode, the date comes from the DB fields. For slug mode, it comes from metadata.published_at.

Renders the OpenGraph + Twitter Card meta tags for a public page from the :og map the controller builds.

Pluralizes a word based on count.

Renders a post's publication date (calendar icon + formatted date).

Resolves the exact language-switcher code to highlight on public pages.

Renders a slim heading-anchor rail on post pages: a fixed side rail with a tick per <h2>/<h3>/<h4> in the article; hover reveals the heading text, click smooth-scrolls to it, and the current section is highlighted as you scroll. Built client-side (assigns heading ids in the browser, so the cached render pipeline is untouched) as a real <nav> of links — keyboard and screen-reader accessible. Hidden on narrow screens; honors reduced-motion.

Renders a thin reading-progress bar fixed to the top of the viewport that fills as the reader scrolls the article. Decorative (aria-hidden), pointer transparent, and honors prefers-reduced-motion.

Renders a date-timeline rail on the group listing: a fixed side rail with a marker per distinct year found across the rendered post cards (which carry a data-post-date); click a year to smooth-scroll to its first post, and the current year highlights as you scroll. Only appears when 2+ years are present. Built client-side as an accessible <nav> of links; hidden on narrow screens.

Emits a <style> that recolors the page's native scrollbar to the daisyUI theme when the group opts into "branded"/"thin". "default" renders nothing (the browser's native bar is untouched). Only recolors/resizes the real scrollbar — scrolling stays native.

Functions

all_groups(assigns)

build_date_counts(posts)

Pre-computes date counts for timestamp-mode posts to avoid per-post DB queries.

Returns a map of %{date_string => count} for use with build_post_url/4 and format_post_date/3.

build_post_url(group_slug, post, language, date_counts \\ nil)

Builds a post URL based on mode. Omits the locale prefix when the site is effectively single-language. Can also omit the default-language prefix when that setting is enabled.

For slug mode posts, uses the language-specific URL slug (from post.url_slug or post.language_slugs[language]) for SEO-friendly localized URLs.

For timestamp mode posts:

  • If only one post exists on the date, uses date-only URL (e.g., /group/2025-12-09)
  • If multiple posts exist on the date, includes time (e.g., /group/2025-12-09/16:26)

build_public_path_with_time(language, group_slug, date, time)

Builds a public path with explicit date and time (always includes time). Used when redirecting from date-only URLs to full timestamp URLs.

build_public_translations(translations, current_language)

Builds language data for the publishing_language_switcher component on public pages. Converts the @translations assign to the format expected by the component.

extract_excerpt(content)

Extracts and renders an excerpt from post content. Returns content before <!-- more --> tag, or first paragraph if no tag. Renders markdown and strips HTML tags for plain text display.

format_date(datetime)

Formats a date for display using locale-aware month names.

format_date_for_url(datetime)

Formats a date for URL.

format_date_with_time(datetime)

Formats a date with time for display. Used when multiple posts exist on the same date.

format_post_date(post, group_slug, date_counts \\ nil)

Formats a post's publication date, including time only when multiple posts exist on the same date.

format_time_for_url(datetime)

Formats time for URL (HH:MM).

group_listing_path(language, group_slug, params \\ [])

Builds the public URL for a group listing page. Omits the locale prefix when the site is effectively single-language. Can also omit the default-language prefix when that setting is enabled.

has_publication_date?(post)

Checks if a post has a publication date to display. For timestamp mode, the date comes from the DB fields. For slug mode, it comes from metadata.published_at.

index(assigns)

og_meta_tags(assigns)

Renders the OpenGraph + Twitter Card meta tags for a public page from the :og map the controller builds.

These are emitted in-page (inside the rendered body) so a social preview works out of the box even when the host's root layout doesn't render the forwarded :og assign in <head> — most host apps ship their own root layout. The same :og map is ALSO forwarded via module_assigns, so a host that does render it in <head> gets the strictly-correct placement; such a host disables the in-page copy via publishing_render_og_tags to avoid duplicate tags. Renders nothing when :og is absent (e.g. the groups index).

Attributes

  • og (:map) - Defaults to nil.

pluralize(count, singular, plural)

Pluralizes a word based on count.

post_date(assigns)

Renders a post's publication date (calendar icon + formatted date).

Attributes

  • post (:map) (required)
  • group_slug (:string) (required)
  • class (:any) - Defaults to nil.

public_current_language(translations, fallback)

Resolves the exact language-switcher code to highlight on public pages.

reading_headings(assigns)

Renders a slim heading-anchor rail on post pages: a fixed side rail with a tick per <h2>/<h3>/<h4> in the article; hover reveals the heading text, click smooth-scrolls to it, and the current section is highlighted as you scroll. Built client-side (assigns heading ids in the browser, so the cached render pipeline is untouched) as a real <nav> of links — keyboard and screen-reader accessible. Hidden on narrow screens; honors reduced-motion.

Attributes

  • enabled (:boolean) - Defaults to false.

reading_progress(assigns)

Renders a thin reading-progress bar fixed to the top of the viewport that fills as the reader scrolls the article. Decorative (aria-hidden), pointer transparent, and honors prefers-reduced-motion.

Attributes

  • enabled (:boolean) - Defaults to false.

scroll_timeline(assigns)

Renders a date-timeline rail on the group listing: a fixed side rail with a marker per distinct year found across the rendered post cards (which carry a data-post-date); click a year to smooth-scroll to its first post, and the current year highlights as you scroll. Only appears when 2+ years are present. Built client-side as an accessible <nav> of links; hidden on narrow screens.

Attributes

  • enabled (:boolean) - Defaults to false.
  • granularity (:string) - Defaults to "auto".

scrollbar_style_tag(assigns)

Emits a <style> that recolors the page's native scrollbar to the daisyUI theme when the group opts into "branded"/"thin". "default" renders nothing (the browser's native bar is untouched). Only recolors/resizes the real scrollbar — scrolling stays native.

Attributes

  • style (:string) - Defaults to "default".

show(assigns)