diff --git a/.formatter.exs b/.formatter.exs index 18b26c5..7675824 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,5 +1,5 @@ [ - import_deps: [:ecto, :ecto_sql, :phoenix], + import_deps: [:ecto, :ecto_sql, :phoenix, :typed_struct], subdirectories: ["priv/*/migrations"], plugins: [Styler, Phoenix.LiveView.HTMLFormatter], inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"] diff --git a/lib/cms/author.ex b/lib/cms/author.ex new file mode 100644 index 0000000..65e38a2 --- /dev/null +++ b/lib/cms/author.ex @@ -0,0 +1,46 @@ +defmodule CMS.Author do + @moduledoc """ + Properties of the author, Sloane + + Modeled after the [h-card] specification. + + [h-card]: https://microformats.org/wiki/h-card + """ + use TypedStruct + + @public_properties ~w[name nickname url]a + + typedstruct do + field :name, String.t() + field :given_name, String.t() + field :additional_name, String.t() + field :family_name, String.t() + field :nickname, String.t() + field :email, String.t() + field :url, String.t() + end + + def sloane do + %__MODULE__{ + name: "Sloane Perrault", + given_name: "Sloane", + additional_name: "Loretta", + family_name: "Perrault", + nickname: "sloanelybutsurely", + email: "sloane@fastmail.com", + url: "https://sloanelybutsurely.com" + } + end + + def full do + sloane() + end + + def public do + author = full() + + for key <- @public_properties, reduce: %__MODULE__{} do + acc -> Map.put(acc, key, Map.get(author, key)) + end + end +end diff --git a/lib/cms_web/components/core_components.ex b/lib/cms_web/components/core_components.ex index 5cb0e5b..70f31e3 100644 --- a/lib/cms_web/components/core_components.ex +++ b/lib/cms_web/components/core_components.ex @@ -109,6 +109,7 @@ defmodule CMSWeb.CoreComponents do attr :format, :string, required: true attr :value, :any, default: nil attr :formatter, :atom, default: :default + attr :timezone, :string, default: "America/New_York" attr :global, :global def timex(%{value: nil} = assigns) do @@ -117,10 +118,27 @@ defmodule CMSWeb.CoreComponents do """ end - def timex(assigns) do + def timex(%{value: value, timezone: timezone} = assigns) do + assigns = + assign_new(assigns, :local_value, fn -> + case value do + %DateTime{} = datetime -> + datetime + + %NaiveDateTime{} = naive -> + naive + |> DateTime.from_naive!("Etc/UTC") + |> DateTime.shift_zone!(timezone) + end + end) + ~H""" - <time datetime={Timex.format!(@value, "{ISO:Extended:Z}")} {@global}> - {Timex.format!(@value, @format, timex_formatter(@formatter))} + <time + datetime={Timex.format!(@local_value, "{ISO:Extended}")} + title={Timex.format!(@local_value, "{Mshort} {D}, {YYYY}, {h12}:{m} {AM} {Zabbr}")} + {@global} + > + {Timex.format!(@local_value, @format, timex_formatter(@formatter))} </time> """ end diff --git a/lib/cms_web/controllers/page_html/home.html.heex b/lib/cms_web/controllers/page_html/home.html.heex index 15a2aa8..83270d6 100644 --- a/lib/cms_web/controllers/page_html/home.html.heex +++ b/lib/cms_web/controllers/page_html/home.html.heex @@ -13,7 +13,11 @@ (no title) <% end %> </span> - <.timex value={post.inserted_at} format="{YYYY}-{0M}-{0D}" class="text-gray-500" /> + <.timex + value={post.inserted_at} + format="{YYYY}-{0M}-{0D}" + class="text-gray-500 text-nowrap" + /> </.link> </li> </ul> @@ -33,7 +37,7 @@ value={status.inserted_at} format="{relative}" formatter={:relative} - class="text-gray-500" + class="text-gray-500 text-nowrap" /> </.link> </li> diff --git a/lib/cms_web/controllers/post_html/index.html.heex b/lib/cms_web/controllers/post_html/index.html.heex index f20baf6..7c6863b 100644 --- a/lib/cms_web/controllers/post_html/index.html.heex +++ b/lib/cms_web/controllers/post_html/index.html.heex @@ -9,7 +9,11 @@ (no title) <% end %> </span> - <.timex value={post.inserted_at} format="{YYYY}-{0M}-{0D}" class="text-gray-500" /> + <.timex + value={post.inserted_at} + format="{YYYY}-{0M}-{0D}" + class="text-gray-500 text-nowrap" + /> </.link> </li> </ul> diff --git a/lib/cms_web/controllers/status_html/index.html.heex b/lib/cms_web/controllers/status_html/index.html.heex index c3105a9..3e21c2a 100644 --- a/lib/cms_web/controllers/status_html/index.html.heex +++ b/lib/cms_web/controllers/status_html/index.html.heex @@ -9,7 +9,7 @@ value={status.inserted_at} format="{relative}" formatter={:relative} - class="text-gray-500" + class="text-gray-500 text-nowrap" /> </.link> </li> diff --git a/mix.exs b/mix.exs index 4465a93..1a94067 100644 --- a/mix.exs +++ b/mix.exs @@ -52,6 +52,7 @@ defmodule CMS.MixProject do {:bandit, "~> 1.5"}, {:argon2_elixir, "~> 4.1"}, {:timex, "~> 3.7"}, + {:typed_struct, "~> 0.3.0"}, # dev/test only {:styler, "~> 1.4", only: [:dev, :test], runtime: false} diff --git a/mix.lock b/mix.lock index 30611a1..c80adeb 100644 --- a/mix.lock +++ b/mix.lock @@ -44,6 +44,7 @@ "telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"}, "thousand_island": {:hex, :thousand_island, "1.3.10", "a9971ebab1dfb36e2710a86b37c3f54973fbc9470d892035334415521fb53328", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "17ab1f1b13aadb1f4b4c8e5b59c06874d701119fed082884c9c6d38addad254f"}, "timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"}, + "typed_struct": {:hex, :typed_struct, "0.3.0", "939789e3c1dca39d7170c87f729127469d1315dcf99fee8e152bb774b17e7ff7", [:mix], [], "hexpm", "c50bd5c3a61fe4e198a8504f939be3d3c85903b382bde4865579bc23111d1b6d"}, "tzdata": {:hex, :tzdata, "1.1.2", "45e5f1fcf8729525ec27c65e163be5b3d247ab1702581a94674e008413eef50b", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "cec7b286e608371602318c414f344941d5eb0375e14cfdab605cca2fe66cba8b"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},