PhoenixKit.Modules.Publishing.Constants (PhoenixKitPublishing v0.9.1)

Copy Markdown View Source

Centralized constants for the Publishing module.

Provides canonical lists for statuses, modes, and types used across schemas, business logic, and templates. Import or alias this module instead of hardcoding these values inline.

For guard clauses and pattern matches, use the module attributes:

@timestamp_modes Publishing.Constants.timestamp_modes()
@slug_modes Publishing.Constants.slug_modes()

def my_func(mode) when mode in @timestamp_modes do ...

Summary

Functions

Valid band styles for the Featured/Latest bands — the PAINT of a band card, orthogonal to its layout (which stays size/placement: hero band vs card in grid): "classic" (image beside/above the text — the original variants), "cover" (the featured image is the card's background, text overlaid on a gradient scrim), "cover_panel" (background image with an opaque text panel), "minimal" (text-only editorial band, image ignored), "top" (16:9 image banner stacked above the text).

Valid version and content statuses: draft, published, archived.

Default band style ("classic" — the pre-styles rendering, unchanged).

Default featured-post layout ("hero").

Default public-listing layout ("grid").

Default public-listing sort order ("newest" first).

Default group mode.

Default latest-post layout ("hero").

Default author-note display style ("footnotes" — the original layout).

Default post-date position ("below" the title).

Default post-page content width ("normal").

Default scrollbar style ("default" — the browser's native bar, untouched).

Default date-timeline granularity ("auto").

Default title for posts without a title.

Default group type.

Valid featured-post layouts: "hero" (band above the grid) or "card" (larger card in the grid).

A site wall-clock date and time back to the true UTC instant — the feed's pubDate. The inverse of to_site_wall/2, resolved for the date given. A wall clock that never happened (spring-forward gap) resolves to the instant the clocks jump to; one that happened twice (fall-back overlap) to its first occurrence — core's parse_datetime_local/2 rules.

Valid group statuses: active, trashed.

Valid public-listing layouts: "grid" (card grid), "list" (thumbnail rows), or "minimal" (date — title lines, no images).

Valid public-listing sort orders: "newest" or "oldest", by effective publish date.

Max length for group names.

Max length for group slugs.

Max length for language codes.

Max length for post/content slugs.

Max length for content titles.

Valid latest-post layouts: "hero" (band above the grid) or "card" (larger card in the grid).

Valid author-note display styles: "footnotes" (numbered refs + a collected bottom section + hover popovers) or "panel" (clicking the phrase slides a right-side panel out with the note and its comments).

Valid post-date positions relative to the title: "above", "below", or "hidden".

Valid post statuses: draft, published, archived, trashed.

Valid post-page content widths: "narrow", "normal", or "wide".

Preset group types (shown as radio buttons in UI).

True for the published status.

True when a timestamp-mode post is scheduled for later and must not be public yet.

Valid scrollbar styles: "default" (native, unstyled), "branded" (theme-colored), "thin" (theme-colored + thin).

Now, on the site's wall clock — the clock timestamp-mode posts are written and displayed on. A UTC-tagged carrier for that wall clock, the same shape to_site_wall/2 hands the stamping path.

The site's time_zone setting — an IANA id such as Europe/Tallinn, or a legacy fixed offset such as "2" on a site that never touched the picker. "0" when settings are unreachable (no DB yet, a sandbox without an owner — Settings.get_setting/2 answers the default itself): UTC is the documented default and a scheduling check must not crash a page.

Returns true if mode is a slug mode (atom or string).

Atom and string variants for slug mode — use in guards/pattern matches.

The "archived" status.

The "draft" status.

The "published" status.

The "trashed" status.

Valid date-timeline granularities: "auto" (fit to the posts' date span), "year", "month", or "day".

Returns true if mode is a timestamp mode (atom or string).

Atom and string variants for timestamp mode — use in guards/pattern matches.

A UTC instant as the site's wall clock, tagged UTC as a carrier — the stamp a timestamp-mode post gets at creation. Resolved for the instant itself, so a named zone follows daylight saving on that date.

Valid mode strings for schema validation.

All valid group types including custom.

Functions

band_styles()

Valid band styles for the Featured/Latest bands — the PAINT of a band card, orthogonal to its layout (which stays size/placement: hero band vs card in grid): "classic" (image beside/above the text — the original variants), "cover" (the featured image is the card's background, text overlaid on a gradient scrim), "cover_panel" (background image with an opaque text panel), "minimal" (text-only editorial band, image ignored), "top" (16:9 image banner stacked above the text).

content_statuses()

Valid version and content statuses: draft, published, archived.

default_band_style()

Default band style ("classic" — the pre-styles rendering, unchanged).

default_listing_layout()

Default public-listing layout ("grid").

default_listing_sort()

Default public-listing sort order ("newest" first).

default_mode()

Default group mode.

default_newest_layout()

Default latest-post layout ("hero").

default_notes_style()

Default author-note display style ("footnotes" — the original layout).

default_post_date_position()

Default post-date position ("below" the title).

default_post_width()

Default post-page content width ("normal").

default_scrollbar_style()

Default scrollbar style ("default" — the browser's native bar, untouched).

default_timeline_granularity()

Default date-timeline granularity ("auto").

default_title()

Default title for posts without a title.

default_type()

Default group type.

from_site_wall(date, time, tz \\ site_tz())

@spec from_site_wall(Date.t(), Time.t() | nil, String.t()) :: DateTime.t()

A site wall-clock date and time back to the true UTC instant — the feed's pubDate. The inverse of to_site_wall/2, resolved for the date given. A wall clock that never happened (spring-forward gap) resolves to the instant the clocks jump to; one that happened twice (fall-back overlap) to its first occurrence — core's parse_datetime_local/2 rules.

group_statuses()

Valid group statuses: active, trashed.

listing_layouts()

Valid public-listing layouts: "grid" (card grid), "list" (thumbnail rows), or "minimal" (date — title lines, no images).

listing_sorts()

Valid public-listing sort orders: "newest" or "oldest", by effective publish date.

max_group_name_length()

Max length for group names.

max_group_slug_length()

Max length for group slugs.

max_language_code_length()

Max length for language codes.

max_slug_length()

Max length for post/content slugs.

max_title_length()

Max length for content titles.

newest_layouts()

Valid latest-post layouts: "hero" (band above the grid) or "card" (larger card in the grid).

notes_styles()

Valid author-note display styles: "footnotes" (numbered refs + a collected bottom section + hover popovers) or "panel" (clicking the phrase slides a right-side panel out with the note and its comments).

post_date_positions()

Valid post-date positions relative to the title: "above", "below", or "hidden".

post_statuses()

Valid post statuses: draft, published, archived, trashed.

post_widths()

Valid post-page content widths: "narrow", "normal", or "wide".

preset_types()

Preset group types (shown as radio buttons in UI).

published?(status)

@spec published?(String.t() | nil) :: boolean()

True for the published status.

Note this is the publishing vocabulary. The comments module has its own "published" status on a different table, and the two are unrelated — a comment being published says nothing about the post it hangs off. Don't reach for this when checking a comment.

scheduled_ahead?(post)

@spec scheduled_ahead?(map()) :: boolean()

True when a timestamp-mode post is scheduled for later and must not be public yet.

A timestamp post is identified by a date AND a time, and the schedule was read as a date alone — so anything set for later today went public at midnight. Nine in the morning is a normal time to line up an announcement for six in the evening, and the listing carried its title, excerpt and image from the moment the day started.

Three copies of the date-only test had drifted into the listing, the post page and the fallback resolver. One predicate, so a scheduled post becomes public at one moment on every path that asks.

post_date/post_time are the SITE's wall clock (stamped and edited in the configured time_zone, shown as-is), so they are first read back as the instant they name — from_site_wall/3, resolved for that date — and that instant is compared with true UTC now. Comparing wall clock to wall clock looked equivalent and was not: a wall clock is not monotonic across a fall-back hour, so a post scheduled inside the hour that repeats went live on the first pass and reverted to "scheduled" on the second, for most of an hour, once a year. Comparing with utc_now/0 DIRECTLY was the earlier bug (an embargoed post released offset hours early west of UTC).

Pass now and tz when testing many posts in one pass — the zone is a settings read, and filter_published/1 runs this over the whole listing cache.

scheduled_ahead?(post, now, tz)

@spec scheduled_ahead?(map(), DateTime.t(), String.t()) :: boolean()

scrollbar_styles()

Valid scrollbar styles: "default" (native, unstyled), "branded" (theme-colored), "thin" (theme-colored + thin).

site_now()

@spec site_now() :: DateTime.t()

Now, on the site's wall clock — the clock timestamp-mode posts are written and displayed on. A UTC-tagged carrier for that wall clock, the same shape to_site_wall/2 hands the stamping path.

Hoist this out of a loop; every call is a settings read.

site_tz()

@spec site_tz() :: String.t()

The site's time_zone setting — an IANA id such as Europe/Tallinn, or a legacy fixed offset such as "2" on a site that never touched the picker. "0" when settings are unreachable (no DB yet, a sandbox without an owner — Settings.get_setting/2 answers the default itself): UTC is the documented default and a scheduling check must not crash a page.

The one place that reading lives, so post stamping, schedule release and feed dates cannot drift apart. It used to be parsed to whole hours with Integer.parse/1, which read an IANA id (and a "5.5") as 0 — every timestamp post stamped, released and syndicated on UTC while the editor saw the site's clock.

slug_mode?(mode)

Returns true if mode is a slug mode (atom or string).

slug_modes()

Atom and string variants for slug mode — use in guards/pattern matches.

status_archived()

The "archived" status.

status_draft()

The "draft" status.

status_published()

The "published" status.

status_trashed()

The "trashed" status.

timeline_granularities()

Valid date-timeline granularities: "auto" (fit to the posts' date span), "year", "month", or "day".

timestamp_mode?(mode)

Returns true if mode is a timestamp mode (atom or string).

timestamp_modes()

Atom and string variants for timestamp mode — use in guards/pattern matches.

to_site_wall(utc, tz \\ site_tz())

@spec to_site_wall(DateTime.t(), String.t()) :: DateTime.t()

A UTC instant as the site's wall clock, tagged UTC as a carrier — the stamp a timestamp-mode post gets at creation. Resolved for the instant itself, so a named zone follows daylight saving on that date.

valid_modes()

Valid mode strings for schema validation.

valid_types()

All valid group types including custom.