diff --git a/assets/tailwind.config.js b/assets/tailwind.config.js
index 76fe451..9f0624b 100644
--- a/assets/tailwind.config.js
+++ b/assets/tailwind.config.js
@@ -6,10 +6,13 @@ let plugin = require('tailwindcss/plugin')
module.exports = {
content: [
'./js/**/*.js',
- '../lib/*_web.ex',
- '../lib/*_web/**/*.*ex'
+ '../lib/sloane_sh/layouts/*.ex',
+ '../priv/site/**/*.*ex',
],
theme: {
+ container: {
+ center: true,
+ },
extend: {},
},
plugins: [
diff --git a/config/config.exs b/config/config.exs
index 39e0e36..f63b335 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -1,13 +1,14 @@
import Config
-config :logger, :default_formatter,
- format: "$time $metadata[$level] $message\n"
+config :logger, :default_formatter, format: "$time $metadata[$level] $message\n"
-config :tailwind, version: "3.4.1", default: [
- args: ~w(
+config :tailwind,
+ version: "3.4.1",
+ default: [
+ args: ~w(
--config=tailwind.config.js
--input=css/app.css
--output=../priv/output/assets/app.css
),
- cd: Path.expand("../assets", __DIR__)
-]
+ cd: Path.expand("../assets", __DIR__)
+ ]
diff --git a/lib/mix/tasks/site.dev.ex b/lib/mix/tasks/site.dev.ex
index ff90ddc..188f8d2 100644
--- a/lib/mix/tasks/site.dev.ex
+++ b/lib/mix/tasks/site.dev.ex
@@ -6,6 +6,7 @@ defmodule Mix.Tasks.Site.Dev do
@impl Mix.Task
def run(_args) do
Mix.Task.run("app.start")
+
{:ok, watch_pid} =
Task.start_link(fn ->
Mix.Task.run("site.watch")
diff --git a/lib/sloane_sh/build.ex b/lib/sloane_sh/build.ex
index 9130216..13af566 100644
--- a/lib/sloane_sh/build.ex
+++ b/lib/sloane_sh/build.ex
@@ -1,18 +1,11 @@
defmodule SloaneSH.Build do
require Logger
- require EEx
alias SloaneSH.Context
+ alias SloaneSH.Layouts
alias SloaneSH.Markdown
alias SloaneSH.Write
- @layouts_dir Path.join(:code.priv_dir(:sloane_sh), "site/layouts")
-
- EEx.function_from_file(:def, :root_layout, Path.join(@layouts_dir, "root.html.eex"), [
- :ctx,
- :inner_content
- ])
-
def run(%Context{} = ctx) do
ctx
|> build_pages()
@@ -37,8 +30,9 @@ defmodule SloaneSH.Build do
path = Path.join(ctx.config.pages_dir, page)
with {:ok, data} <- File.read(path),
- {:ok, inner_content} <- Markdown.transform(ctx, data),
- html = root_layout(ctx, inner_content),
+ {:ok, md} <- Markdown.transform(ctx, data),
+ contents = Layouts.page_layout(ctx, md.attrs, md.html),
+ html = Layouts.root_layout(ctx, md.attrs, contents),
:ok <- Write.page(ctx, page, html) do
Logger.info("Built page: #{page}")
else
@@ -50,8 +44,8 @@ defmodule SloaneSH.Build do
path = Path.join(ctx.config.posts_dir, post)
with {:ok, data} <- File.read(path),
- {:ok, html} <- Markdown.transform(ctx, data),
- :ok <- Write.post(ctx, post, html) do
+ {:ok, md} <- Markdown.transform(ctx, data),
+ :ok <- Write.post(ctx, post, md.html) do
Logger.info("Built post: #{post}")
else
err -> Logger.error("Failed to build post #{post}: #{inspect(err)}")
diff --git a/lib/sloane_sh/layouts.ex b/lib/sloane_sh/layouts.ex
new file mode 100644
index 0000000..a2c909f
--- /dev/null
+++ b/lib/sloane_sh/layouts.ex
@@ -0,0 +1,27 @@
+defmodule SloaneSH.Layouts do
+ @moduledoc """
+ `EEx` based layouts
+ """
+ require EEx
+ import SloaneSH.Layouts.Partials
+
+ @layouts_dir Path.join(:code.priv_dir(:sloane_sh), "site/layouts")
+
+ EEx.function_from_file(:def, :root_layout, Path.join(@layouts_dir, "root.html.eex"), [
+ :ctx,
+ :attrs,
+ :inner_content
+ ])
+
+ EEx.function_from_file(:def, :page_layout, Path.join(@layouts_dir, "page.html.eex"), [
+ :ctx,
+ :attrs,
+ :inner_content
+ ])
+
+ EEx.function_from_file(:def, :post_layout, Path.join(@layouts_dir, "post.html.eex"), [
+ :ctx,
+ :attrs,
+ :inner_content
+ ])
+end
diff --git a/lib/sloane_sh/layouts/partials.ex b/lib/sloane_sh/layouts/partials.ex
new file mode 100644
index 0000000..1c1f75c
--- /dev/null
+++ b/lib/sloane_sh/layouts/partials.ex
@@ -0,0 +1,16 @@
+defmodule SloaneSH.Layouts.Partials do
+ @moduledoc """
+ HTML partials for use in HTML layouts
+ """
+
+ def header(_ctx) do
+ ~s"""
+
+ """
+ end
+end
diff --git a/lib/sloane_sh/markdown.ex b/lib/sloane_sh/markdown.ex
index a418871..9c6becc 100644
--- a/lib/sloane_sh/markdown.ex
+++ b/lib/sloane_sh/markdown.ex
@@ -3,19 +3,52 @@ defmodule SloaneSH.Markdown do
Markdown parsing using `Earmark` and `Earmark.Parser`
"""
require Logger
+ use TypedStruct
alias SloaneSH.Context
+ alias __MODULE__
- def transform(%Context{} = _ctx, data) when is_binary(data) do
- case Earmark.as_html(data) do
- {:ok, html_doc, deprecation_messages} ->
- for msg <- deprecation_messages, do: Logger.warning(msg)
+ typedstruct do
+ field :attrs, map(), default: %{}
+ field :html, String.t(), default: ""
+ end
- {:ok, html_doc}
+ def transform(%Context{} = ctx, data) when is_binary(data) do
+ data
+ |> parse_attrs(ctx)
+ |> parse_markdown(ctx)
+ end
- {:error, html_doc, error_messages} ->
- for msg <- error_messages, do: Logger.error(msg)
- {:error, html_doc}
+ defp parse_attrs("+++" <> rest, _ctx) do
+ [toml, body] = String.split(rest, ["+++\n", "+++\r\n"], parts: 2)
+
+ with {:ok, attrs} <- Toml.decode(toml, keys: :atoms) do
+ {:ok, attrs, body}
end
end
+
+ defp parse_attrs(body, _ctx) do
+ {:ok, %{}, body}
+ end
+
+ defp parse_markdown({:ok, attrs, body}, _ctx) do
+ with {:ok, html, msgs} <- Earmark.as_html(body) do
+ for msg <- msgs, do: Logger.warning(msg)
+
+ {:ok,
+ %Markdown{
+ attrs: attrs,
+ html: html
+ }}
+ else
+ {:error, _, msgs} ->
+ for msg <- msgs, do: Logger.error(msg)
+ :error
+
+ _ ->
+ :error
+ end
+ end
+
+ defp parse_markdown(other, _ctx), do: other
end
diff --git a/lib/sloane_sh/watch.ex b/lib/sloane_sh/watch.ex
index 87ce35a..11754de 100644
--- a/lib/sloane_sh/watch.ex
+++ b/lib/sloane_sh/watch.ex
@@ -5,6 +5,7 @@ defmodule SloaneSH.Watch do
alias SloaneSH.Build
alias SloaneSH.Context
+ alias SloaneSH.Layouts
typedstruct do
field :ctx, Context.t(), enforce: true
@@ -19,17 +20,21 @@ defmodule SloaneSH.Watch do
def init(%Context{} = ctx) do
{:ok, watcher_pid} =
FileSystem.start_link(
- dirs: [
- # ctx.config.layouts_dir,
- "priv/site/layouts",
- ctx.config.pages_dir,
- ctx.config.posts_dir
- ]
+ dirs:
+ [
+ # ctx.config.layouts_dir,
+ "priv/site/layouts",
+ ctx.config.pages_dir,
+ ctx.config.posts_dir
+ ]
+ |> dbg()
)
- FileSystem.subscribe(watcher_pid)
+ :ok = FileSystem.subscribe(watcher_pid)
- Tailwind.install_and_run(:default, ~w[--watch]) |> dbg()
+ Task.start_link(fn ->
+ Tailwind.install_and_run(:default, ~w[--watch])
+ end)
state = %__MODULE__{ctx: ctx, watcher_pid: watcher_pid}
@@ -45,8 +50,10 @@ defmodule SloaneSH.Watch do
@impl GenServer
def handle_info({:file_event, pid, {path, events}}, %{ctx: ctx, watcher_pid: pid} = state) do
+ dbg(path)
+
if String.match?(path, ~r/layouts/) do
- recompile_build()
+ recompile_layouts()
Build.run(ctx)
{:noreply, state}
else
@@ -70,9 +77,9 @@ defmodule SloaneSH.Watch do
{:stop, :watcher_stopped, pid}
end
- defp recompile_build do
- build_source = Build.module_info(:compile)[:source] |> List.to_string()
- {:ok, _, _} = Kernel.ParallelCompiler.compile([build_source])
+ defp recompile_layouts do
+ layouts_source = Layouts.module_info(:compile)[:source] |> List.to_string()
+ {:ok, _, _} = Kernel.ParallelCompiler.compile([layouts_source])
:ok
end
diff --git a/mix.exs b/mix.exs
index f0eb7cc..04ea82e 100644
--- a/mix.exs
+++ b/mix.exs
@@ -28,7 +28,8 @@ defmodule SloaneSH.MixProject do
{:earmark_parser, "~> 1.4"},
{:plug, "~> 1.15"},
{:bandit, "~> 1.2"},
- {:tailwind, "~> 0.2"}
+ {:tailwind, "~> 0.2"},
+ {:toml, "~> 0.7"}
]
end
diff --git a/mix.lock b/mix.lock
index ccba40b..5ddf801 100644
--- a/mix.lock
+++ b/mix.lock
@@ -11,6 +11,7 @@
"tailwind": {:hex, :tailwind, "0.2.2", "9e27288b568ede1d88517e8c61259bc214a12d7eed271e102db4c93fcca9b2cd", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "ccfb5025179ea307f7f899d1bb3905cd0ac9f687ed77feebc8f67bdca78565c4"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"thousand_island": {:hex, :thousand_island, "1.3.2", "bc27f9afba6e1a676dd36507d42e429935a142cf5ee69b8e3f90bff1383943cd", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0e085b93012cd1057b378fce40cbfbf381ff6d957a382bfdd5eca1a98eec2535"},
+ "toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"},
"typed_struct": {:hex, :typed_struct, "0.3.0", "939789e3c1dca39d7170c87f729127469d1315dcf99fee8e152bb774b17e7ff7", [:mix], [], "hexpm", "c50bd5c3a61fe4e198a8504f939be3d3c85903b382bde4865579bc23111d1b6d"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
}
diff --git a/priv/site/layouts/page.html.eex b/priv/site/layouts/page.html.eex
new file mode 100644
index 0000000..fb81838
--- /dev/null
+++ b/priv/site/layouts/page.html.eex
@@ -0,0 +1 @@
+<%= inner_content %>
diff --git a/priv/site/layouts/pages.html.eex b/priv/site/layouts/pages.html.eex
deleted file mode 100644
index e69de29..0000000
diff --git a/priv/site/layouts/post.html.eex b/priv/site/layouts/post.html.eex
new file mode 100644
index 0000000..fb81838
--- /dev/null
+++ b/priv/site/layouts/post.html.eex
@@ -0,0 +1 @@
+<%= inner_content %>
diff --git a/priv/site/layouts/posts.html.eex b/priv/site/layouts/posts.html.eex
deleted file mode 100644
index e69de29..0000000
diff --git a/priv/site/layouts/root.html.eex b/priv/site/layouts/root.html.eex
index 3eb4fac..d337acb 100644
--- a/priv/site/layouts/root.html.eex
+++ b/priv/site/layouts/root.html.eex
@@ -1,18 +1,13 @@
-
+
- sloane.sh
+ sloane.sh | <%= attrs[:title] %>
-
-
+
+ <%= header(ctx) %>
<%= inner_content %>
diff --git a/priv/site/pages/index.md b/priv/site/pages/index.md
index 23013fa..aea72c0 100644
--- a/priv/site/pages/index.md
+++ b/priv/site/pages/index.md
@@ -1,6 +1,12 @@
++++
+permalink = "/"
+title = "home"
++++
+
# Hello, World!
my name is sloane. i am a software engineer.
-
i'm on the fediverse [@sloane@tech.lgbt](https://tech.lgbt/@sloane)
+
+also on [github](https://github.com/sloanelybutsurely).